summaryrefslogtreecommitdiff
path: root/src/components/include/utils
diff options
context:
space:
mode:
authorJustin Dickow <jjdickow@gmail.com>2015-02-20 09:11:18 -0500
committerJustin Dickow <jjdickow@gmail.com>2015-02-20 09:11:18 -0500
commita7c5d752cb75485baa0ded5226335d0f8eb10321 (patch)
treefbfd9251ada2cdcd5cf6a03a79887d08f6b496d7 /src/components/include/utils
parentb2b2233d866f102d3de339afa8ccaf37d3cf2570 (diff)
downloadsmartdevicelink-SynchronizationCommit.tar.gz
Bug Fixes and ImprovementsSynchronizationCommit
Fix Empty perform iteration request Fix type of name from string to enum SendLocation implemented on HTML5 HMI Fixed PI response on VR rejection due to high priority. Fix Apps not responsive/not able to start app/apps remain listed on SYNC even after USB disconnect Mobile API change and processing capabilities Change perform interaction request conditions. Fix SDL must always start 3sec timer before resuming the HMILevel of the app Remove redundant StartSavePersistentDataTimer() call. Change wrong predicate name to right. Added stream request handling feature Made streaming timeout in media manager configurable Put navi app in LIMITED in case of phone call Handling of audio state for applications Add stop streaming timeout into ini file Implement HMILevel resumption for job-1 Fix result code ABORTED when interrupts it by Voice recognition activation Fix incorrect value parameter unexpectedDisconnect in BCOnAppUnregistered Fix SDL send BC.OnAppUnregistered with "unexpectedDisconnect" set to "true" in case received from HMI OnExitAllApplications {"reason":"MASTER_RESET"} Fix Update ini file for iAP1 support Current working directory added to image path Fix helpers to make it workable with more then 2 parameters DCHECK() for ManageMobileCommand() replaced with log message because the latter returns false in some regular situations (e.g. TOO_MANY_PENDING_REQUESTS, see SDLAQ-CRS-10) Remove connection after closing. Signed-off-by: Justin Dickow <jjdickow@gmail.com>
Diffstat (limited to 'src/components/include/utils')
-rw-r--r--src/components/include/utils/atomic.h8
-rw-r--r--src/components/include/utils/conditional_variable.h6
-rw-r--r--src/components/include/utils/data_accessor.h38
-rw-r--r--src/components/include/utils/date_time.h64
-rw-r--r--src/components/include/utils/lock.h28
-rw-r--r--src/components/include/utils/logger.h24
-rw-r--r--src/components/include/utils/logger_status.h2
-rw-r--r--src/components/include/utils/macro.h56
-rw-r--r--src/components/include/utils/memory_barrier.h2
-rw-r--r--src/components/include/utils/message_queue.h15
-rw-r--r--src/components/include/utils/prioritized_queue.h2
-rw-r--r--src/components/include/utils/rwlock.h95
-rw-r--r--src/components/include/utils/shared_ptr.h5
-rw-r--r--src/components/include/utils/threads/CMakeLists.txt5
-rw-r--r--src/components/include/utils/threads/message_loop_thread.h54
-rw-r--r--src/components/include/utils/threads/thread.h146
-rw-r--r--src/components/include/utils/threads/thread_delegate.h64
-rw-r--r--src/components/include/utils/threads/thread_options.h4
-rw-r--r--src/components/include/utils/timer_thread.h450
19 files changed, 660 insertions, 408 deletions
diff --git a/src/components/include/utils/atomic.h b/src/components/include/utils/atomic.h
index bfbcff9dc..f80455b74 100644
--- a/src/components/include/utils/atomic.h
+++ b/src/components/include/utils/atomic.h
@@ -28,15 +28,15 @@
* 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_INCLUDE_UTILS_ATOMIC_H_
+#define SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_
#ifdef __QNXNTO__
#include <atomic.h>
#endif
-#ifndef SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_
-#define SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_
-
#if defined(__QNXNTO__)
#define atomic_post_inc(ptr) atomic_add_value((ptr), 1)
#elif defined(__GNUG__)
diff --git a/src/components/include/utils/conditional_variable.h b/src/components/include/utils/conditional_variable.h
index 58119a0cf..1f0a7e62d 100644
--- a/src/components/include/utils/conditional_variable.h
+++ b/src/components/include/utils/conditional_variable.h
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2013, Ford Motor Company
* All rights reserved.
*
@@ -43,6 +43,7 @@
namespace sync_primitives {
class AutoLock;
+class Lock;
namespace impl {
#if defined(OS_POSIX)
@@ -80,7 +81,8 @@ class ConditionalVariable {
void Broadcast();
// Wait forever or up to milliseconds time limit
- void Wait(AutoLock& auto_lock);
+ bool Wait(AutoLock& auto_lock);
+ bool Wait(Lock& lock);
WaitStatus WaitFor(AutoLock& auto_lock, int32_t milliseconds);
private:
impl::PlatformConditionalVariable cond_var_;
diff --git a/src/components/include/utils/data_accessor.h b/src/components/include/utils/data_accessor.h
index f5e99797b..344d6e34a 100644
--- a/src/components/include/utils/data_accessor.h
+++ b/src/components/include/utils/data_accessor.h
@@ -33,40 +33,42 @@
#define SRC_COMPONENTS_INCLUDE_UTILS_DATA_ACCESSOR_H_
#include "utils/lock.h"
+#include "utils/shared_ptr.h"
// This class is for thread-safe access to data
template<class T>
class DataAccessor {
public:
DataAccessor(const T& data, const sync_primitives::Lock& lock)
- : data_(data)
- , lock_(const_cast<sync_primitives::Lock&>(lock))
- , counter_(0) {
- lock_.Acquire();
+ : data_(data),
+ lock_(const_cast<sync_primitives::Lock&>(lock)),
+ counter_( new uint32_t(0)) {
+ lock_.Acquire();
}
- template<class O> DataAccessor(const DataAccessor<O>& other)
- : data_(other.data_)
- , lock_(other.lock_)
- , counter_(other.counter_) {
- ++counter_;
+
+ DataAccessor(const DataAccessor<T>& other)
+ : data_(other.data_),
+ lock_(other.lock_),
+ counter_(other.counter_) {
+ ++(*counter_);
}
+
~DataAccessor() {
- if (counter_ > 0) {
- --counter_;
- }
- if (0 == counter_) {
- lock_.Release();
+ if (0 == *counter_) {
+ lock_.Release();
+ } else {
+ --(*counter_);
}
}
const T& GetData() const {
return data_;
}
private:
- template <class O> const DataAccessor<T>& operator=(const DataAccessor<O>& other);
- const T& data_;
- sync_primitives::Lock& lock_;
- uint32_t counter_;
+ void *operator new(size_t size);
+ const T& data_;
+ sync_primitives::Lock& lock_;
+ utils::SharedPtr<uint32_t> counter_;
};
#endif // SRC_COMPONENTS_INCLUDE_UTILS_DATA_ACCESSOR_H_
diff --git a/src/components/include/utils/date_time.h b/src/components/include/utils/date_time.h
index 766932652..c8cef32ef 100644
--- a/src/components/include/utils/date_time.h
+++ b/src/components/include/utils/date_time.h
@@ -1,34 +1,34 @@
/*
-* Copyright (c) 2014, Ford Motor Company
-* All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions are met:
-*
-* Redistributions of source code must retain the above copyright notice, this
-* list of conditions and the following disclaimer.
-*
-* Redistributions in binary form must reproduce the above copyright notice,
-* this list of conditions and the following
-* disclaimer in the documentation and/or other materials provided with the
-* distribution.
-*
-* Neither the name of the Ford Motor Company nor the names of its contributors
-* may be used to endorse or promote products derived from this software
-* without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-* 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.
-*/
+ * Copyright (c) 2014, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * 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_INCLUDE_UTILS_DATE_TIME_H_
#define SRC_COMPONENTS_INCLUDE_UTILS_DATE_TIME_H_
@@ -50,6 +50,7 @@ class DateTime {
public:
static const int32_t MILLISECONDS_IN_SECOND = 1000;
static const int32_t MICROSECONDS_IN_MILLISECONDS = 1000;
+ static const int32_t MICROSECONDS_IN_SECOND = 1000 * 1000;
static TimevalStruct getCurrentTime();
@@ -80,5 +81,6 @@ class DateTime {
};
} // namespace date_time
-
+bool operator<(const TimevalStruct& time1, const TimevalStruct& time2);
+bool operator==(const TimevalStruct& time1, const TimevalStruct& time2);
#endif // SRC_COMPONENTS_INCLUDE_UTILS_DATE_TIME_H_
diff --git a/src/components/include/utils/lock.h b/src/components/include/utils/lock.h
index 910a88052..29bd46714 100644
--- a/src/components/include/utils/lock.h
+++ b/src/components/include/utils/lock.h
@@ -34,11 +34,14 @@
#if defined(OS_POSIX)
#include <pthread.h>
+#include <sched.h>
#else
#error Please implement lock for your OS
#endif
#include <stdint.h>
#include "utils/macro.h"
+#include "utils/atomic.h"
+#include "utils/memory_barrier.h"
namespace sync_primitives {
@@ -48,6 +51,31 @@ typedef pthread_mutex_t PlatformMutex;
#endif
} // namespace impl
+
+class SpinMutex {
+ public:
+ SpinMutex()
+ : state_(0) { }
+ void Lock() {
+ if (atomic_post_set(&state_) == 0) {
+ return;
+ }
+ for(;;) {
+ sched_yield();
+ if (state_ == 0 && atomic_post_set(&state_) == 0) {
+ return;
+ }
+ }
+ }
+ void Unlock() {
+ state_ = 0;
+ }
+ ~SpinMutex() {
+ }
+ private:
+ volatile unsigned int state_;
+};
+
/* Platform-indepenednt NON-RECURSIVE lock (mutex) wrapper
Please use AutoLock to ackquire and (automatically) release it
It eases balancing of multple lock taking/releasing and makes it
diff --git a/src/components/include/utils/logger.h b/src/components/include/utils/logger.h
index 7c00c5d3a..50d194245 100644
--- a/src/components/include/utils/logger.h
+++ b/src/components/include/utils/logger.h
@@ -30,6 +30,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+
+
#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_
#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_
@@ -37,11 +39,11 @@
#include <errno.h>
#include <string.h>
#include <sstream>
- #include <apr_time.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/spi/loggingevent.h>
#include "utils/push_log.h"
#include "utils/logger_status.h"
+ #include "utils/auto_trace.h"
#endif // ENABLE_LOG
#ifdef ENABLE_LOG
@@ -57,19 +59,23 @@
#define INIT_LOGGER(file_name) \
log4cxx::PropertyConfigurator::configure(file_name);
- // without this line log4cxx threads continue using some instances destroyed by exit()
- #define DEINIT_LOGGER() \
- log4cxx::Logger::getRootLogger()->closeNestedAppenders();
+ // Logger deinitilization function and macro, need to stop log4cxx writing
+ // without this deinitilization log4cxx threads continue using some instances destroyed by exit()
+ void deinit_logger ();
+ #define DEINIT_LOGGER() deinit_logger()
#define LOG4CXX_IS_TRACE_ENABLED(logger) logger->isTraceEnabled()
+ log4cxx_time_t time_now();
+
#define LOG_WITH_LEVEL(loggerPtr, logLevel, logEvent) \
do { \
if (logger::logger_status != logger::DeletingLoggerThread) { \
if (loggerPtr->isEnabledFor(logLevel)) { \
std::stringstream accumulator; \
accumulator << logEvent; \
- logger::push_log(loggerPtr, logLevel, accumulator.str(), apr_time_now(), LOG4CXX_LOCATION, ::log4cxx::spi::LoggingEvent::getCurrentThreadName()); \
+ logger::push_log(loggerPtr, logLevel, accumulator.str(), time_now(), \
+ LOG4CXX_LOCATION, ::log4cxx::spi::LoggingEvent::getCurrentThreadName()); \
} \
} \
} while (false)
@@ -110,8 +116,8 @@
#undef LOG4CXX_TRACE
#define LOG4CXX_TRACE(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getTrace(), logEvent)
- #define LOG4CXX_TRACE_ENTER(logger) LOG4CXX_TRACE(logger, "ENTER: " << __PRETTY_FUNCTION__ )
- #define LOG4CXX_TRACE_EXIT(logger) LOG4CXX_TRACE(logger, "EXIT: " << __PRETTY_FUNCTION__ )
+ #define LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, auto_trace) logger::AutoTrace auto_trace(loggerPtr, LOG4CXX_LOCATION)
+ #define LOG4CXX_AUTO_TRACE(loggerPtr) LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, SDL_local_auto_trace_object)
#define LOG4CXX_ERROR_WITH_ERRNO(logger, message) \
LOG4CXX_ERROR(logger, message << ", error code " << errno << " (" << strerror(errno) << ")")
@@ -173,8 +179,8 @@
#define LOG4CXX_FATAL_EXT(logger, logEvent)
#define LOG4CXX_FATAL_STR_EXT(logger, logEvent)
- #define LOG4CXX_TRACE_ENTER(logger)
- #define LOG4CXX_TRACE_EXIT(logger)
+ #define LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, auto_trace)
+ #define LOG4CXX_AUTO_TRACE(loggerPtr)
#endif // ENABLE_LOG
#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_
diff --git a/src/components/include/utils/logger_status.h b/src/components/include/utils/logger_status.h
index e28fa6f83..17fa0562c 100644
--- a/src/components/include/utils/logger_status.h
+++ b/src/components/include/utils/logger_status.h
@@ -45,7 +45,7 @@ typedef enum {
// this variable is only changed when creating and deleting logger thread
// its reads and writes are believed to be atomic
// thus it shall be considered thread safe
-extern LoggerStatus logger_status;
+extern volatile LoggerStatus logger_status;
} // namespace logger
diff --git a/src/components/include/utils/macro.h b/src/components/include/utils/macro.h
index bf34b199b..bfd13411f 100644
--- a/src/components/include/utils/macro.h
+++ b/src/components/include/utils/macro.h
@@ -32,8 +32,12 @@
#ifndef SRC_COMPONENTS_INCLUDE_UTILS_MACRO_H_
#define SRC_COMPONENTS_INCLUDE_UTILS_MACRO_H_
+#ifdef DEBUG
#include <assert.h>
+#else // RELEASE
#include <stdio.h>
+#endif
+#include "logger.h"
@@ -54,14 +58,53 @@
#define FRIEND_DELETER_DESTRUCTOR(TypeName) \
friend utils::deleters::Deleter<TypeName>::~Deleter()
+#ifdef DEBUG
+ #define ASSERT(condition) \
+ do { \
+ DEINIT_LOGGER(); \
+ assert(condition); \
+ } while (false)
+#else // RELEASE
+ #define ASSERT(condition) \
+ fprintf(stderr, "Failed condition \"" #condition "\" [%s:%d][%s]\n\n", \
+ __FILE__, __LINE__, __FUNCTION__)
+#endif
+
#define DCHECK(condition) \
if (!(condition)) { \
- printf("\nDCHECK [%s:%d][%s]", __FILE__, __LINE__, __FUNCTION__); \
- printf("[Check failed: " #condition "]\n\n"); \
- assert(false); \
+ CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \
+ LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \
+ << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']'); \
+ ASSERT((condition)); \
+ }
+
+/*
+ * Will cauch assert on debug version,
+ * Will return return_value in release build
+ */
+#define DCHECK_OR_RETURN(condition, return_value) \
+ if (!(condition)) { \
+ CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \
+ LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \
+ << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']' ); \
+ ASSERT((condition)); \
+ return (return_value); \
+ }
+/*
+ * Will cauch assert on debug version,
+ * Will return return_value in release build
+ */
+#define DCHECK_OR_RETURN_VOID(condition) \
+ if (!(condition)) { \
+ CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \
+ LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \
+ << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']' ); \
+ ASSERT((condition)); \
+ return ; \
}
-#define NOTREACHED() DCHECK(false)
+
+#define NOTREACHED() DCHECK(!"Unreachable code")
// Allows to perform static check that virtual function from base class is
// actually being overriden if compiler support is available
@@ -79,4 +122,9 @@
*/
#define ARRAYSIZE(arr) sizeof (arr) / sizeof(*arr)
+#ifdef BUILD_TESTS
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+#endif
+
#endif // SRC_COMPONENTS_INCLUDE_UTILS_MACRO_H_
diff --git a/src/components/include/utils/memory_barrier.h b/src/components/include/utils/memory_barrier.h
index 312894e03..43c7c9df1 100644
--- a/src/components/include/utils/memory_barrier.h
+++ b/src/components/include/utils/memory_barrier.h
@@ -28,7 +28,7 @@
* 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_MEMORY_BARRIER_H_
#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_MEMORY_BARRIER_H_
diff --git a/src/components/include/utils/message_queue.h b/src/components/include/utils/message_queue.h
index 9d998cc69..a187328e1 100644
--- a/src/components/include/utils/message_queue.h
+++ b/src/components/include/utils/message_queue.h
@@ -28,10 +28,10 @@
* 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 MESSAGE_QUEUE_CLASS
-#define MESSAGE_QUEUE_CLASS
+#ifndef SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_
+#define SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_
#include <queue>
@@ -44,7 +44,9 @@
* \class MessageQueue
* \brief Wrapper for multithreading queue.
*/
- //TODO(Ezamakhov): move to utils namespace
+
+namespace utils {
+
template<typename T, class Q = std::queue<T> > class MessageQueue {
public:
typedef Q Queue;
@@ -107,7 +109,6 @@ template<typename T, class Q = std::queue<T> > class MessageQueue {
void Reset();
private:
-
/**
*\brief Queue
*/
@@ -193,4 +194,6 @@ template<typename T, class Q> void MessageQueue<T, Q>::Reset() {
}
}
-#endif // MESSAGE_QUEUE_CLASS
+} // namespace utils
+
+#endif // SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_
diff --git a/src/components/include/utils/prioritized_queue.h b/src/components/include/utils/prioritized_queue.h
index 4bec901f5..2a8ebf0a7 100644
--- a/src/components/include/utils/prioritized_queue.h
+++ b/src/components/include/utils/prioritized_queue.h
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2013, Ford Motor Company
* All rights reserved.
*
diff --git a/src/components/include/utils/rwlock.h b/src/components/include/utils/rwlock.h
index b5042acbf..1083dbd63 100644
--- a/src/components/include/utils/rwlock.h
+++ b/src/components/include/utils/rwlock.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Ford Motor Company
+ * Copyright (c) 2015, Ford Motor Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,8 +30,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RWLOCK_H_
-#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RWLOCK_H_
+#ifndef SRC_COMPONENTS_INCLUDE_UTILS_RWLOCK_H_
+#define SRC_COMPONENTS_INCLUDE_UTILS_RWLOCK_H_
#if defined(OS_POSIX)
#include <pthread.h>
@@ -49,21 +49,91 @@ typedef pthread_rwlock_t PlatformRWLock;
#endif
} // namespace impl
+/**
+ * RW locks wrapper
+ * Read-write locks permit concurrent reads and exclusive writes to a protected shared resource.
+ * The read-write lock is a single entity that can be locked in read or write mode.
+ * To modify a resource, a thread must first acquire the exclusive write lock.
+ * An exclusive write lock is not permitted until all read locks have been released.
+ */
+
class RWLock {
public:
RWLock();
~RWLock();
- void AcquireForReading();
- void AcquireForWriting();
- void Release();
+
+ /**
+ * @brief Acqure read-write lock for reading.
+ * The calling thread acquires the read lock if a writer does not
+ * hold the lock and there are no writers blocked on the lock.
+ * It is unspecified whether the calling thread acquires the lock
+ * when a writer does not hold the lock and there are writers waiting for the lock.
+ * If a writer holds the lock, the calling thread will not acquire the read lock.
+ * If the read lock is not acquired, the calling thread blocks
+ * (that is, it does not return from the AcquireForReading()) until it can acquire the lock.
+ * Results are undefined if the calling thread holds a write lock on rwlock at the time the call is made.
+ * A thread can hold multiple concurrent read locks on rwlock
+ * (that is, successfully call AcquireForReading() n times)
+ * If so, the thread must perform matching unlocks (that is, it must call Release() n times).
+ * @returns true if lock was acquired and false if was not
+ */
+ bool AcquireForReading();
+
+ /**
+ * @brief try to Acqure read-write lock for reading.
+ * Applies a read lock as in AcquireForReading()
+ * with the exception that the function fails if any thread
+ * holds a write lock on rwlock or there are writers blocked on rwlock.
+ * But not blocks calling thread.
+ * @returns true if lock was acquired and false if was not
+ */
+ bool TryAcquireForReading();
+
+ /**
+ * @brief Try to Acqure read-write lock for writing.
+ * Applies a write lock like AcquireForWriting(), with the exception that the
+ * function fails if any thread currently holds rwlock (for reading or writing)
+ * Invoke of TryAcquireForWriting will not block calling thread and returns "false"
+ * @returns true if lock was acquired and false if was not
+ */
+ bool TryAcquireForWriting();
+
+ /**
+ * @brief Acqure read-write lock for writing.
+ * Applies a write lock to the read-write lock.
+ * The calling thread acquires the write lock if no other thread (reader or writer)
+ * holds the read-write lock rwlock. Otherwise, the thread blocks
+ * (that is, does not return from the AcquireForWriting() call)
+ * until it can acquire the lock.
+ * Results are undefined if the calling thread holds the read-write lock (whether a read or write lock)
+ * at the time the call is made.
+ * The thread must perform matching unlock (that is, it must call Release()).
+ * @returns true if lock was acquired and false if was not
+ */
+ bool AcquireForWriting();
+
+ /**
+ * @brief Release read-write lock.
+ * Releases a lock held on the read-write lock object.
+ * Results are undefined if the read-write lock rwlock
+ * is not held by the calling thread.
+ * @returns true if lock was released and false if was not
+ */
+ bool Release();
private:
impl::PlatformRWLock rwlock_;
};
+/**
+ * @brief Makes auto lock read-write locks for reading
+ * Please use AutoReadLock to acquire for reading and (automatically) release it
+ */
+
class AutoReadLock {
public:
- explicit AutoReadLock(RWLock& rwlock) : rwlock_(rwlock) {
+ explicit AutoReadLock(RWLock& rwlock)
+ : rwlock_(rwlock) {
rwlock_.AcquireForReading();
}
~AutoReadLock() {
@@ -72,13 +142,17 @@ class AutoReadLock {
private:
RWLock& rwlock_;
-
DISALLOW_COPY_AND_ASSIGN(AutoReadLock);
};
+/**
+ * @brief Makes auto lock read-write locks for writing
+ * Please use AutoWriteLock to acquire for writing and (automatically) release it
+ */
class AutoWriteLock {
public:
- explicit AutoWriteLock(RWLock& rwlock) : rwlock_(rwlock) {
+ explicit AutoWriteLock(RWLock& rwlock)
+ : rwlock_(rwlock) {
rwlock_.AcquireForWriting();
}
~AutoWriteLock() {
@@ -87,10 +161,9 @@ class AutoWriteLock {
private:
RWLock& rwlock_;
-
DISALLOW_COPY_AND_ASSIGN(AutoWriteLock);
};
} // namespace sync_primitives
-#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RWLOCK_H_
+#endif // SRC_COMPONENTS_INCLUDE_UTILS_RWLOCK_H_
diff --git a/src/components/include/utils/shared_ptr.h b/src/components/include/utils/shared_ptr.h
index 604bee998..f506c6018 100644
--- a/src/components/include/utils/shared_ptr.h
+++ b/src/components/include/utils/shared_ptr.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2013, Ford Motor Company
* All rights reserved.
*
@@ -164,7 +164,6 @@ class SharedPtr {
operator bool() const;
void reset();
void reset(ObjectType* other);
- void release();
ObjectType* get() const;
/**
@@ -197,6 +196,8 @@ class SharedPtr {
* @brief Pointer to reference counter.
**/
uint32_t* mReferenceCounter;
+
+ void release();
};
template<typename ObjectType>
diff --git a/src/components/include/utils/threads/CMakeLists.txt b/src/components/include/utils/threads/CMakeLists.txt
new file mode 100644
index 000000000..f97039c21
--- /dev/null
+++ b/src/components/include/utils/threads/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(UtilsIncludeDir ${COMPONENTS_DIR/utils/include)
+
+include_directories (
+ ${UtilsIncludeDir}
+) \ No newline at end of file
diff --git a/src/components/include/utils/threads/message_loop_thread.h b/src/components/include/utils/threads/message_loop_thread.h
index e051c4890..6f90df209 100644
--- a/src/components/include/utils/threads/message_loop_thread.h
+++ b/src/components/include/utils/threads/message_loop_thread.h
@@ -39,13 +39,16 @@
#include "utils/logger.h"
#include "utils/macro.h"
#include "utils/message_queue.h"
-#include "utils/threads/thread_manager.h"
-#include "utils/lock.h"
+#include "utils/threads/thread.h"
+#include "utils/shared_ptr.h"
namespace threads {
-/*
- * Class that handles a thread which sole purpose is to pump messages pushed
+using ::utils::MessageQueue;
+
+/**
+ * \class MessageLoopThread
+ * \brief Handles a thread which sole purpose is to pump messages pushed
* to it's queue. To handle messages someone, Handler must be implemented and
* passed to MessageLoopThread constructor.
*/
@@ -79,6 +82,10 @@ class MessageLoopThread {
// Places a message to the therad's queue. Thread-safe.
void PostMessage(const Message& message);
+
+ // Process already posted messages and stop thread processing. Thread-safe.
+ void Shutdown();
+
private:
/*
* Implementation of ThreadDelegate that actually pumps the queue and is
@@ -90,19 +97,20 @@ class MessageLoopThread {
// threads::ThreadDelegate overrides
virtual void threadMain() OVERRIDE;
- virtual bool exitThreadMain() OVERRIDE;
+ virtual void exitThreadMain() OVERRIDE;
+
private:
// Handle all messages that are in the queue until it is empty
void DrainQue();
- private:
// Handler that processes messages
Handler& handler_;
// Message queue that is actually owned by MessageLoopThread
MessageQueue<Message, Queue>& message_queue_;
- sync_primitives::Lock active_lock;
};
+
private:
MessageQueue<Message, Queue> message_queue_;
+ LoopThreadDelegate* thread_delegate_;
threads::Thread* thread_;
};
@@ -112,8 +120,10 @@ template<class Q>
MessageLoopThread<Q>::MessageLoopThread(const std::string& name,
Handler* handler,
const ThreadOptions& thread_opts)
- : thread_(threads::CreateThread(name.c_str(), new LoopThreadDelegate(&message_queue_, handler))) {
- bool started = thread_->startWithOptions(thread_opts);
+ : thread_delegate_(new LoopThreadDelegate(&message_queue_, handler)),
+ thread_(threads::CreateThread(name.c_str(),
+ thread_delegate_)) {
+ const bool started = thread_->start(thread_opts);
if (!started) {
CREATE_LOGGERPTR_LOCAL(logger_, "Utils")
LOG4CXX_ERROR(logger_, "Failed to start thread " << name);
@@ -122,7 +132,10 @@ MessageLoopThread<Q>::MessageLoopThread(const std::string& name,
template<class Q>
MessageLoopThread<Q>::~MessageLoopThread() {
- thread_->stop();
+ Shutdown();
+ thread_->join();
+ delete thread_delegate_;
+ threads::DeleteThread(thread_);
}
template <class Q>
@@ -130,6 +143,11 @@ void MessageLoopThread<Q>::PostMessage(const Message& message) {
message_queue_.push(message);
}
+template <class Q>
+void MessageLoopThread<Q>::Shutdown() {
+ thread_->stop();
+}
+
//////////
template<class Q>
MessageLoopThread<Q>::LoopThreadDelegate::LoopThreadDelegate(
@@ -142,8 +160,9 @@ MessageLoopThread<Q>::LoopThreadDelegate::LoopThreadDelegate(
template<class Q>
void MessageLoopThread<Q>::LoopThreadDelegate::threadMain() {
- sync_primitives::AutoLock auto_lock(active_lock);
- while(!message_queue_.IsShuttingDown()){
+ CREATE_LOGGERPTR_LOCAL(logger_, "Utils")
+ LOG4CXX_AUTO_TRACE(logger_);
+ while (!message_queue_.IsShuttingDown()) {
DrainQue();
message_queue_.wait();
}
@@ -152,18 +171,15 @@ void MessageLoopThread<Q>::LoopThreadDelegate::threadMain() {
}
template<class Q>
-bool MessageLoopThread<Q>::LoopThreadDelegate::exitThreadMain() {
+void MessageLoopThread<Q>::LoopThreadDelegate::exitThreadMain() {
+ CREATE_LOGGERPTR_LOCAL(logger_, "Utils")
+ LOG4CXX_AUTO_TRACE(logger_);
message_queue_.Shutdown();
- {
- sync_primitives::AutoLock auto_lock(active_lock);
- // Prevent canceling thread until queue is drained
- }
- return true;
}
template<class Q>
void MessageLoopThread<Q>::LoopThreadDelegate::DrainQue() {
- while(!message_queue_.empty()) {
+ while (!message_queue_.empty()) {
handler_.Handle(message_queue_.pop());
}
}
diff --git a/src/components/include/utils/threads/thread.h b/src/components/include/utils/threads/thread.h
index 3b81cf345..fd2b5e9fd 100644
--- a/src/components/include/utils/threads/thread.h
+++ b/src/components/include/utils/threads/thread.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Ford Motor Company
+ * Copyright (c) 2015, Ford Motor Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,19 +43,19 @@
#include "utils/macro.h"
#include "utils/threads/thread_delegate.h"
#include "utils/threads/thread_options.h"
+#include "utils/conditional_variable.h"
+#include "utils/lock.h"
namespace threads {
-namespace impl {
#if defined(OS_POSIX)
typedef pthread_t PlatformThreadHandle;
#else
#error Please implement thread for your OS
#endif
-}
/**
- * Non platform specific thread abstraction that establishes a
+ * @brief Non platform specific thread abstraction that establishes a
* threads::ThreadDelegate on a new thread.
*
* ThreadDelegate example:
@@ -75,60 +75,72 @@ typedef pthread_t PlatformThreadHandle;
* thread.join();
* printf("ok!\n");
*/
+
class Thread;
+void enqueue_to_join(Thread* thread);
+
Thread* CreateThread(const char* name, ThreadDelegate* delegate);
-void DeleteThread(Thread*);
+void DeleteThread(Thread* thread);
class Thread {
- friend Thread* CreateThread(const char*, ThreadDelegate*);
- friend void DeleteThread(Thread*);
- public:
- /**
- * Class that represents unique in-process thread identifier
- * due to restriction of pthread API it only allows checks
- * for equality to different thread id and no ordering.
- *
- * ostream<< operator is provided for this class which
- * outputs thread name associated to an identifier.
- */
- class Id {
- public:
- explicit Id(const impl::PlatformThreadHandle& id): id_(id) {}
- bool operator==(const Id& that) const;
- impl::PlatformThreadHandle Handle() const { return id_; }
- private:
- impl::PlatformThreadHandle id_;
- friend class Thread;
- };
-
- // Get unique ID of currently executing thread
- static Id CurrentId();
-
- // Get name associated with thread identified by thread_id
- static std::string NameFromId(const Id& thread_id);
-
- // Give thread thread_id a name, helpful for debugging
- static void SetNameForId(const Id& thread_id, const std::string& name);
+ private:
+ const std::string name_;
+ // Should be locked to protect delegate_ value
+ sync_primitives::Lock delegate_lock_;
+ ThreadDelegate* delegate_;
+ PlatformThreadHandle handle_;
+ ThreadOptions thread_options_;
+ // Should be locked to protect isThreadRunning_ and thread_created_ values
+ sync_primitives::Lock state_lock_;
+ volatile unsigned int isThreadRunning_;
+ volatile bool stopped_;
+ volatile bool finalized_;
+ bool thread_created_;
+ // Signalled when Thread::start() is called
+ sync_primitives::ConditionalVariable run_cond_;
+ public:
/**
- * Starts the thread.
+ * @brief Starts the thread.
* @return true if the thread was successfully started.
*/
bool start();
- ThreadDelegate* delegate() const;
-
/**
- * Starts the thread. Behaves exactly like Start in addition to
+ * @brief Starts the thread. Behaves exactly like \ref start() in addition to
* allow to override the default options.
- * @param options - thread options. Look for 'threads/thread_options.h'
+ * @param options Thread options. Look for 'threads/thread_options.h'
* for details.
* @return true if the thread was successfully started.
*/
- bool startWithOptions(const ThreadOptions& options);
+ bool start(const ThreadOptions& options);
+
+ sync_primitives::Lock& delegate_lock() {
+ return delegate_lock_;
+ }
+
+ ThreadDelegate *delegate() const {
+ return delegate_;
+ }
+
+ void set_delegate(ThreadDelegate *delegate) {
+ DCHECK(!isThreadRunning_);
+ delegate_ = delegate;
+ }
+
+ friend Thread* CreateThread(const char* name, ThreadDelegate* delegate);
+ friend void DeleteThread(Thread* thread);
+
+ public:
+ // Get unique ID of currently executing thread
+ static PlatformThreadHandle CurrentId();
+
+ // Give thread thread_id a name, helpful for debugging
+ static void SetNameForId(const PlatformThreadHandle& thread_id,
+ std::string name);
/**
- * Signals the thread to exit and returns once the thread has exited.
+ * @brief Signals the thread to exit and returns once the thread has exited.
* After this method returns, the Thread object is completely reset and may
* be used as if it were newly constructed (i.e., Start may be called again).
*
@@ -137,16 +149,18 @@ class Thread {
*/
void stop();
+ void join();
+
/**
- * Get thread name.
+ * @brief Get thread name.
* @return thread name
*/
- const std::string& thread_name() {
+ const std::string& name() {
return name_;
}
/**
- * Returns true if the thread has been started, and not yet stopped.
+ * @brief Returns true if the thread has been started, and not yet stopped.
* When a thread is running, the thread_id_ is non-zero.
* @return true if the thread has been started, and not yet stopped.
*/
@@ -154,12 +168,10 @@ class Thread {
return isThreadRunning_;
}
- void set_running(bool running) {
- isThreadRunning_ = running;
- }
+ void set_running(bool running);
/**
- * Is thread joinable?
+ * @brief Is thread joinable?
* @return - Returns true if the thread is joinable.
*/
bool is_joinable() const {
@@ -167,7 +179,7 @@ class Thread {
}
/**
- * Thread stack size
+ * @brief Thread stack size
* @return thread stack size
*/
size_t stack_size() const {
@@ -175,23 +187,15 @@ class Thread {
}
/**
- * The native thread handle.
+ * @brief The native thread handle.
* @return thread handle.
*/
- impl::PlatformThreadHandle thread_handle() const {
- return thread_handle_;
- }
-
- /**
- * Thread id.
- * @return return thread id.
- */
- Id thread_id() const {
- return Id(thread_handle());
+ PlatformThreadHandle thread_handle() const {
+ return handle_;
}
/**
- * Thread options.
+ * @brief Thread options.
* @return thread options.
*/
const ThreadOptions& thread_options() const {
@@ -199,16 +203,12 @@ class Thread {
}
/**
- * Minimum size of thread stack for specific platform.
+ * @brief Minimum size of thread stack for specific platform.
*/
static size_t kMinStackSize;
protected:
- const std::string name_;
- ThreadDelegate* delegate_;
- impl::PlatformThreadHandle thread_handle_;
- ThreadOptions thread_options_;
- volatile unsigned int isThreadRunning_;
+ sync_primitives::ConditionalVariable state_cond_;
private:
/**
@@ -216,19 +216,17 @@ class Thread {
* @param name - display string to identify the thread.
* @param delegate - thread procedure delegate. Look for
* 'threads/thread_delegate.h' for details.
- * NOTE: delegate will be deleted by destructor.
+ * LifeCycle thread , otherwise it will be joined in stop method
+ * NOTE: delegate will be deleted after thread will be joined
* This constructor made private to prevent
* Thread object to be created on stack
*/
Thread(const char* name, ThreadDelegate* delegate);
-
+ virtual ~Thread();
+ static void* threadFunc(void* arg);
+ static void cleanup(void* arg);
DISALLOW_COPY_AND_ASSIGN(Thread);
- virtual ~Thread() { }
};
-inline bool operator!= (const Thread::Id& left, const Thread::Id& right) {
- return !(left == right);
-}
-std::ostream& operator<<(std::ostream& os, const Thread::Id& thread_id);
} // namespace threads
#endif // SRC_COMPONENTS_INCLUDE_UTILS_THREADS_THREAD_H_
diff --git a/src/components/include/utils/threads/thread_delegate.h b/src/components/include/utils/threads/thread_delegate.h
index 47e68f1e8..66ad30241 100644
--- a/src/components/include/utils/threads/thread_delegate.h
+++ b/src/components/include/utils/threads/thread_delegate.h
@@ -35,30 +35,66 @@
#include <pthread.h>
+#include "utils/lock.h"
+
namespace threads {
+enum ThreadState {
+ kInit = 0,
+ kStarted = 1,
+ kStopReq = 2
+};
+
+class Thread;
+
/**
* Thread procedure interface.
* Look for "threads/thread.h" for example
*/
class ThreadDelegate {
- public:
+ public:
+ ThreadDelegate()
+ : state_(kInit),
+ thread_(NULL) {
+ }
+ /**
+ * \brief Thread procedure.
+ */
+ virtual void threadMain() = 0;
+
+ /**
+ * Should be called to free all resources allocated in threadMain
+ * and exiting threadMain
+ * This function should be blocking and return only when threadMain() will be
+ * finished in other case segmantation failes are possible
+ */
+ virtual void exitThreadMain();
- /**
- * Thread procedure.
- */
- virtual void threadMain() = 0;
+ virtual ~ThreadDelegate();
- /**
- * Should be called to free all resources allocated in threadMain
- * and exiting threadMain
- * This function should be blocking and return only when threadMain() will be
- * finished in other case segmantation failes are possible
- */
- virtual bool exitThreadMain() {
- return false;
+ Thread* thread() const {
+ return thread_;
+ }
+
+ void set_thread(Thread *thread);
+
+ bool ImproveState(unsigned int to) {
+ state_lock_.Lock();
+ if ((state_ + 1 == to) || (to == kInit && state_ == kStopReq)) {
+ state_ = to;
}
- virtual ~ThreadDelegate() { }
+ state_lock_.Unlock();
+ return state_ == to;
+ }
+
+ unsigned int state() const {
+ return state_;
+ }
+
+ private:
+ volatile unsigned int state_;
+ sync_primitives::SpinMutex state_lock_;
+ Thread* thread_;
};
} // namespace threads
diff --git a/src/components/include/utils/threads/thread_options.h b/src/components/include/utils/threads/thread_options.h
index 217f0815a..797ee0693 100644
--- a/src/components/include/utils/threads/thread_options.h
+++ b/src/components/include/utils/threads/thread_options.h
@@ -38,7 +38,7 @@
namespace threads {
/**
- * @breif Startup options for thread.
+ * @brief Startup options for thread.
* Look for "threads/thread.h" for example
*/
class ThreadOptions {
@@ -74,7 +74,7 @@ class ThreadOptions {
* @param options - new options.
* @return new options.
*/
- ThreadOptions& operator=(const ThreadOptions& options ) {
+ ThreadOptions& operator=(const ThreadOptions& options) {
stack_size_ = options.stack_size();
is_joinable_ = options.is_joinable();
return *this;
diff --git a/src/components/include/utils/timer_thread.h b/src/components/include/utils/timer_thread.h
index a3481e4b4..eaa67effe 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,345 @@ 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 method suspends timer execution
+ */
+ virtual void pause();
+
+ /**
+ * @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();
-
- /*
- * @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);
- threads::Thread* thread_;
- protected:
-
- /**
- * @brief Interface called by delegator on timeout
- */
- void onTimeOut() const;
-
- private:
-
+ 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);
+ };
+
+ /**
+ * @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_AUTO_TRACE(logger_);
+ if (isRunning()) {
LOG4CXX_INFO(logger_, "TimerThread start needs stop " << name_);
stop();
}
+ updateTimeOut(timeout_seconds);
+ thread_->start();
+}
- delegate_ = is_looper_ ?
- new TimerLooperDelegate(this) :
- new TimerDelegate(this);
- delegate_->setTimeOut(timeout_seconds);
-
- thread_ = threads::CreateThread("TimerThread", delegate_);
- if (delegate_ && thread_) {
- is_running_ = true;
- thread_->start();
- }
+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>
+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>
+void TimerThread<T>::pause() {
+ LOG4CXX_DEBUG(logger_, "Suspension of timer " << name_);
+ const uint32_t wait_seconds = std::numeric_limits<uint32_t>::max();
+ updateTimeOut(wait_seconds);
}
-template <class T>
+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) {
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();
+ return;
+ } else {
+ LOG4CXX_DEBUG(logger_,
+ "Timeout reset force: " << TimerDelegate::timeout_seconds_);
+ return;
}
}
- 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() {
+template<class T>
+void TimerThread<T>::TimerDelegate::exitThreadMain() {
sync_primitives::AutoLock auto_lock(state_lock_);
stop_flag_ = true;
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>
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_