diff options
Diffstat (limited to 'src/components/include/utils')
23 files changed, 1497 insertions, 1113 deletions
diff --git a/src/components/include/utils/atomic_object.h b/src/components/include/utils/atomic_object.h new file mode 100644 index 0000000000..257fcfbe3a --- /dev/null +++ b/src/components/include/utils/atomic_object.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, 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_ATOMIC_OBJECT_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_OBJECT_H_ + +#include "utils/rwlock.h" +#include "utils/conditional_variable.h" +#include "utils/macro.h" + +namespace sync_primitives { + +/** + * @brief Allows to safely change stored value from different threads. + * + * The usage example: + * + * threads::Atomic<int> i; + * + * i = 5; // here SDL is able to guarantee that this value will be safely + * // assigned even in multi threaded environment. + */ +template <typename T> +class Atomic { + public: + /** + * @brief Atomic allows to construct atomic object. + * The operation is not atomic. + * + * @param value the value to initialize object with. + */ + Atomic(const T& value) : value_(value) {} + + /** + * @brief operator = thread safe setter for stored value. + * + * @param val value to assign. + * + * @return mofified value. + */ + T& operator=(const T& val) { + sync_primitives::AutoWriteLock lock(rw_lock_); + value_ = val; + return value_; + } + + /** + * @brief operator T thread safe getter + * + * return stored value. + */ + operator T() const { + sync_primitives::AutoReadLock lock(rw_lock_); + return value_; + } + + /** + * @brief operator T thread safe getter + * + * return stored value. + */ + template <typename U> + operator U() const { + sync_primitives::AutoReadLock lock(rw_lock_); + return static_cast<U>(value_); + } + + private: + T value_; + mutable sync_primitives::RWLock rw_lock_; +}; + +typedef Atomic<int> atomic_int; +typedef Atomic<int32_t> atomic_int32; +typedef Atomic<uint32_t> atomic_uint32; +typedef Atomic<int64_t> atomic_int64; +typedef Atomic<uint64_t> atomic_uint64; +typedef Atomic<size_t> atomic_size_t; +typedef Atomic<bool> atomic_bool; + +} // namespace sync_primitives + +#endif // SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_OBJECT_H_ diff --git a/src/components/include/utils/auto_trace.h b/src/components/include/utils/auto_trace.h index 87b6554808..36ff3be281 100644 --- a/src/components/include/utils/auto_trace.h +++ b/src/components/include/utils/auto_trace.h @@ -40,10 +40,8 @@ namespace logger { class AutoTrace { public: - AutoTrace( - log4cxx::LoggerPtr logger, - const log4cxx::spi::LocationInfo& location - ); + AutoTrace(log4cxx::LoggerPtr logger, + const log4cxx::spi::LocationInfo& location); ~AutoTrace(); private: diff --git a/src/components/include/utils/conditional_variable.h b/src/components/include/utils/conditional_variable.h index 1f0a7e62de..f54a22e993 100644 --- a/src/components/include/utils/conditional_variable.h +++ b/src/components/include/utils/conditional_variable.h @@ -83,7 +83,8 @@ class ConditionalVariable { // Wait forever or up to milliseconds time limit bool Wait(AutoLock& auto_lock); bool Wait(Lock& lock); - WaitStatus WaitFor(AutoLock& auto_lock, int32_t milliseconds); + WaitStatus WaitFor(AutoLock& auto_lock, uint32_t milliseconds); + private: impl::PlatformConditionalVariable cond_var_; diff --git a/src/components/include/utils/custom_string.h b/src/components/include/utils/custom_string.h new file mode 100644 index 0000000000..7b21e7a64d --- /dev/null +++ b/src/components/include/utils/custom_string.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015, 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_CUSTOM_STRING_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_CUSTOM_STRING_H_ + +#include <string> + +namespace utils { +namespace custom_string { +/* UTF8 formats: + * UTF8 1 byte consists from one-byte sequence + * bit representation of one character: 0xxxxxxx + * UTF8 2 bytes consists from two-byte sequence + * bit representation of one character: 110xxxxx 10xxxxxx + * UTF8 3 bytes consists from three-byte sequence + * bit representation of one character: 1110xxxx 10xxxxxx 10xxxxxx + * UTF8 4 bytes consists from four-byte sequence + * bit representation of one character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ +enum UTFFormat { + kByteOfUTF8 = 0x80, // 10xxxxxx + kHigestByteOfUTF8Byte2 = 0xc0, // 110xxxxx + kHigestByteOfUTF8Byte3 = 0xe0, // 1110xxxx + kHigestByteOfUTF8Byte4 = 0xf0 // 11110xxx +}; + +class CustomString { + public: + /** + * @brief Constructs empty object. + */ + CustomString(); + + /** + * @brief Constructs object with copy of str. + * @param Contains string for new object. + */ + explicit CustomString(const std::string& str); + + /** + * @brief Constructs object with copy of str. + * @param Contains pointer to string for new object. + */ + explicit CustomString(const char* str); + + /** + * @brief Constructs object with n consecutive copies of character c. + * @param Contains amount of copies of character for new object. + * @param Contains character for new object. + */ + CustomString(size_t n, char c); + + /** + * @brief Returns the length of the string, in terms of characters. + */ + size_t size() const; + + /** + * @brief Returns the length of the string, in terms of characters. + */ + size_t length() const; + + /** + * @brief Returns the length of the string, in terms of bytes. + */ + size_t length_bytes() const; + + /** + * @brief Returns TRUE if CustomString contains ASCII string + * otherwise returns FALSE. + */ + bool is_ascii_string() const; + + /** + * @brief Returns TRUE if CustomString contains empty string + * otherwise returns FALSE. + */ + bool empty() const; + + /** + * @brief Compares the value of the string (case sensitive). + * @param Contains string for comparing + * @return Returns TRUE if strings is equal otherwise returns FALSE. + */ + bool operator==(const CustomString& str) const; + + /** + * @brief Compares the value of the string (case sensitive). + * @param Contains string for comparing + * @return Returns TRUE if strings is equal otherwise returns FALSE. + */ + bool operator==(const std::string& str) const; + + /** + * @brief Assigns a new value to the string + * @param Contains string for assignment + * @return Returns result of assignment + */ + CustomString& operator=(const char* str); + + /** + * @brief Concatenates string from CustomString with string from argument. + * @param Contains string for concatenation. + * @return Returns result of concatenation. + */ + CustomString operator+(const CustomString& str) const; + + /** + * @brief Concatenates string from CustomString with string from argument. + * @param Contains string for concatenation. + * @return Returns result of concatenation. + */ + CustomString operator+(const std::string& str) const; + + /** + * @brief Returns the character at position pos in the string. + * Need to use with ASCII string. + * @param pos value with the position of a character within the string. + */ + char at(size_t pos) const; + + /** + * @brief Compares the value of the string (case sensitive). + * @param Contains string for comparing + * @return Returns 0 if strings is equal otherwise + * returns "<0" or ">0". + */ + int compare(const char* str) const; + + /** + * @brief Compares the value of the string (case sensitive). + * @param Contains string for comparing + * @return Returns 0 if strings is equal otherwise + * returns "<0" or ">0". + */ + int compare(const std::string& str) const; + + /** + * @brief Compares the value of the string (case insensitive). + * @param Contains string for comparing + * @return Returns TRUE if strings is equal otherwise returns FALSE. + */ + bool CompareIgnoreCase(const CustomString& str) const; + + /** + * @brief Compares the value of the string (case insensitive). + * @param Contains string for comparing + * @return Returns TRUE if strings is equal otherwise returns FALSE. + */ + bool CompareIgnoreCase(const char* str) const; + + /** + * @brief Returns a pointer to string from CustomString. + */ + const char* c_str() const; + + /** + * @brief Converts string to unicode string. + * @return Returns unicode string. + */ + std::wstring ToWString() const; + + /** + * @brief Returns copy of string as multibyte string. + */ + std::string AsMBString() const; + + /** + * @brief Converts string to lower case unicode string. + * @return Returns unicode string. + */ + std::wstring ToWStringLowerCase() const; + + private: + /** + * @brief Initiates members of CustomString + */ + void InitData(); + + std::string mb_string_; + size_t amount_characters_; + bool is_ascii_string_; +}; + +} // namespace custom_string +} // namespace utils + +#endif // SRC_COMPONENTS_INCLUDE_UTILS_CUSTOM_STRING_H_ diff --git a/src/components/include/utils/data_accessor.h b/src/components/include/utils/data_accessor.h index 344d6e34a8..9be28a638b 100644 --- a/src/components/include/utils/data_accessor.h +++ b/src/components/include/utils/data_accessor.h @@ -36,26 +36,24 @@ #include "utils/shared_ptr.h" // This class is for thread-safe access to data -template<class T> +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_( new uint32_t(0)) { + : data_(data) + , lock_(const_cast<sync_primitives::Lock&>(lock)) + , counter_(new uint32_t(0)) { lock_.Acquire(); } DataAccessor(const DataAccessor<T>& other) - : data_(other.data_), - lock_(other.lock_), - counter_(other.counter_) { + : data_(other.data_), lock_(other.lock_), counter_(other.counter_) { ++(*counter_); } ~DataAccessor() { if (0 == *counter_) { - lock_.Release(); + lock_.Release(); } else { --(*counter_); } @@ -63,9 +61,9 @@ class DataAccessor { const T& GetData() const { return data_; } - private: - void *operator new(size_t size); + private: + void* operator new(size_t size); const T& data_; sync_primitives::Lock& lock_; utils::SharedPtr<uint32_t> counter_; diff --git a/src/components/include/utils/date_time.h b/src/components/include/utils/date_time.h index c8cef32ef4..f8f8e3d6ce 100644 --- a/src/components/include/utils/date_time.h +++ b/src/components/include/utils/date_time.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 @@ -40,17 +40,18 @@ typedef struct timeval TimevalStruct; namespace date_time { -enum TimeCompare { - LESS, - EQUAL, - GREATER -}; +enum TimeCompare { LESS, EQUAL, GREATER }; 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 const int32_t MICROSECONDS_IN_MILLISECOND = 1000; + static const int32_t NANOSECONDS_IN_MICROSECOND = 1000; + static const int32_t SECONDS_IN_HOUR = 3600; + static const int32_t MICROSECONDS_IN_SECOND = + MILLISECONDS_IN_SECOND * MICROSECONDS_IN_MILLISECOND; + static const int32_t NANOSECONDS_IN_MILLISECOND = + MICROSECONDS_IN_MILLISECOND * NANOSECONDS_IN_MICROSECOND; static TimevalStruct getCurrentTime(); @@ -69,6 +70,14 @@ class DateTime { static int64_t calculateTimeDiff(const TimevalStruct& time1, const TimevalStruct& time2); + /** + * @brief Adds milliseconds to time struct + * @param time contains time struct + * @param milliseconds contains value which need to + * add to time struct + **/ + static void AddMilliseconds(TimevalStruct& time, uint32_t milliseconds); + static TimevalStruct Sub(const TimevalStruct& time1, const TimevalStruct& time2); @@ -78,9 +87,14 @@ class DateTime { static bool Greater(const TimevalStruct& time1, const TimevalStruct& time2); static bool Less(const TimevalStruct& time1, const TimevalStruct& time2); static bool Equal(const TimevalStruct& time1, const TimevalStruct& time2); + + private: + static TimevalStruct ConvertionUsecs(const TimevalStruct& time); }; } // namespace date_time bool operator<(const TimevalStruct& time1, const TimevalStruct& time2); bool operator==(const TimevalStruct& time1, const TimevalStruct& time2); +const TimevalStruct 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 29bd467143..e615a58f9d 100644 --- a/src/components/include/utils/lock.h +++ b/src/components/include/utils/lock.h @@ -49,19 +49,21 @@ namespace impl { #if defined(OS_POSIX) typedef pthread_mutex_t PlatformMutex; #endif -} // namespace impl - +} // namespace impl class SpinMutex { public: - SpinMutex() - : state_(0) { } + SpinMutex() : state_(0) {} void Lock() { + // Comment below add exception for lint error + // Reason: FlexeLint doesn't know about compiler's built-in instructions + /*lint -e1055*/ if (atomic_post_set(&state_) == 0) { return; } - for(;;) { + for (;;) { sched_yield(); + /*lint -e1055*/ if (state_ == 0 && atomic_post_set(&state_) == 0) { return; } @@ -70,8 +72,8 @@ class SpinMutex { void Unlock() { state_ = 0; } - ~SpinMutex() { - } + ~SpinMutex() {} + private: volatile unsigned int state_; }; @@ -92,7 +94,7 @@ class SpinMutex { class Lock { public: Lock(); - Lock(bool is_mutex_recursive); + Lock(bool is_recursive); ~Lock(); // Ackquire the lock. Must be called only once on a thread. @@ -113,7 +115,8 @@ class Lock { #ifndef NDEBUG /** - * @brief Basic debugging aid, a flag that signals wether this lock is currently taken + * @brief Basic debugging aid, a flag that signals wether this lock is + * currently taken * Allows detection of abandoned and recursively captured mutexes */ uint32_t lock_taken_; @@ -130,6 +133,7 @@ class Lock { void AssertTakenAndMarkFree() {} #endif + void Init(bool is_recursive); friend class ConditionalVariable; DISALLOW_COPY_AND_ASSIGN(Lock); @@ -138,11 +142,17 @@ class Lock { // This class is used to automatically acquire and release the a lock class AutoLock { public: - explicit AutoLock(Lock& lock) - : lock_(lock) { lock_.Acquire(); } - ~AutoLock() { lock_.Release(); } + explicit AutoLock(Lock& lock) : lock_(lock) { + lock_.Acquire(); + } + ~AutoLock() { + lock_.Release(); + } + private: - Lock& GetLock(){ return lock_; } + Lock& GetLock() { + return lock_; + } Lock& lock_; private: @@ -154,9 +164,16 @@ class AutoLock { // This class is used to temporarly unlock autolocked lock class AutoUnlock { public: - explicit AutoUnlock(AutoLock& lock) - : lock_(lock.GetLock()) { lock_.Release(); } - ~AutoUnlock() { lock_.Acquire(); } + explicit AutoUnlock(Lock& lock) : lock_(lock) { + lock_.Release(); + } + explicit AutoUnlock(AutoLock& lock) : lock_(lock.GetLock()) { + lock_.Release(); + } + ~AutoUnlock() { + lock_.Acquire(); + } + private: Lock& lock_; diff --git a/src/components/include/utils/logger.h b/src/components/include/utils/logger.h index 50d194245c..11a2f1f0d9 100644 --- a/src/components/include/utils/logger.h +++ b/src/components/include/utils/logger.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,157 +30,145 @@ * POSSIBILITY OF SUCH DAMAGE. */ - - -#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_ -#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_ +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_LOGGER_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_LOGGER_H_ #ifdef ENABLE_LOG - #include <errno.h> - #include <string.h> - #include <sstream> - #include <log4cxx/propertyconfigurator.h> - #include <log4cxx/spi/loggingevent.h> - #include "utils/push_log.h" - #include "utils/logger_status.h" - #include "utils/auto_trace.h" +#include <errno.h> +#include <string.h> +#include <sstream> +#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 - #define CREATE_LOGGERPTR_GLOBAL(logger_var, logger_name) \ - namespace { \ - CREATE_LOGGERPTR_LOCAL(logger_var, logger_name); \ - } - - #define CREATE_LOGGERPTR_LOCAL(logger_var, logger_name) \ - log4cxx::LoggerPtr logger_var = log4cxx::LoggerPtr(log4cxx::Logger::getLogger(logger_name)); - - #define INIT_LOGGER(file_name) \ - log4cxx::PropertyConfigurator::configure(file_name); - - // 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(), time_now(), \ - LOG4CXX_LOCATION, ::log4cxx::spi::LoggingEvent::getCurrentThreadName()); \ - } \ - } \ - } while (false) - - #undef LOG4CXX_INFO - #define LOG4CXX_INFO(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getInfo(), logEvent) - - #define LOG4CXX_INFO_EXT(logger, logEvent) LOG4CXX_INFO(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - #define LOG4CXX_INFO_STR_EXT(logger, logEvent) LOG4CXX_INFO_STR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - - #define LOG4CXX_TRACE_EXT(logger, logEvent) LOG4CXX_TRACE(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - #define LOG4CXX_TRACE_STR_EXT(logger, logEvent) LOG4CXX_TRACE_STR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - - #undef LOG4CXX_DEBUG - #define LOG4CXX_DEBUG(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getDebug(), logEvent) - - #define LOG4CXX_DEBUG_EXT(logger, logEvent) LOG4CXX_DEBUG(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - #define LOG4CXX_DEBUG_STR_EXT(logger, logEvent) LOG4CXX_DEBUG_STR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) +#define CREATE_LOGGERPTR_GLOBAL(logger_var, logger_name) \ + namespace { \ + CREATE_LOGGERPTR_LOCAL(logger_var, logger_name); \ + } - #undef LOG4CXX_WARN - #define LOG4CXX_WARN(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getWarn(), logEvent) +#define CREATE_LOGGERPTR_LOCAL(logger_var, logger_name) \ + log4cxx::LoggerPtr logger_var = \ + log4cxx::LoggerPtr(log4cxx::Logger::getLogger(logger_name)); - #define LOG4CXX_WARN_EXT(logger, logEvent) LOG4CXX_WARN(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - #define LOG4CXX_WARN_STR_EXT(logger, logEvent) LOG4CXX_WARN_STR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) +#define INIT_LOGGER(file_name, logs_enabled) \ + log4cxx::PropertyConfigurator::configure(file_name); \ + logger::set_logs_enabled(logs_enabled); - #undef LOG4CXX_ERROR - #define LOG4CXX_ERROR(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getError(), logEvent) +// 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_ERROR_EXT(logger, logEvent) LOG4CXX_ERROR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - #define LOG4CXX_ERROR_STR_EXT(logger, logEvent) LOG4CXX_ERROR_STR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) +// special macros to dump logs from queue +// it's need, for example, when crash happend +#define FLUSH_LOGGER() logger::flush_logger() - #undef LOG4CXX_FATAL - #define LOG4CXX_FATAL(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getFatal(), logEvent) +#define LOG4CXX_IS_TRACE_ENABLED(logger) logger->isTraceEnabled() - #define LOG4CXX_FATAL_EXT(logger, logEvent) LOG4CXX_FATAL(logger, __PRETTY_FUNCTION__ << ": " << logEvent) - #define LOG4CXX_FATAL_STR_EXT(logger, logEvent) LOG4CXX_FATAL_STR(logger, __PRETTY_FUNCTION__ << ": " << logEvent) +log4cxx_time_t time_now(); - #undef LOG4CXX_TRACE - #define LOG4CXX_TRACE(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getTrace(), logEvent) +#define LOG_WITH_LEVEL(loggerPtr, logLevel, logEvent) \ + do { \ + if (logger::logs_enabled()) { \ + if (logger::logger_status != logger::DeletingLoggerThread) { \ + if (loggerPtr->isEnabledFor(logLevel)) { \ + std::stringstream accumulator; \ + accumulator << logEvent; \ + logger::push_log( \ + loggerPtr, \ + logLevel, \ + accumulator.str(), \ + time_now(), \ + LOG4CXX_LOCATION, \ + ::log4cxx::spi::LoggingEvent::getCurrentThreadName()); \ + } \ + } \ + } \ + } while (false) - #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) +#undef LOG4CXX_TRACE +#define LOG4CXX_TRACE(loggerPtr, logEvent) \ + LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getTrace(), logEvent) - #define LOG4CXX_ERROR_WITH_ERRNO(logger, message) \ - LOG4CXX_ERROR(logger, message << ", error code " << errno << " (" << strerror(errno) << ")") +#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_WARN_WITH_ERRNO(logger, message) \ - LOG4CXX_WARN(logger, message << ", error code " << errno << " (" << strerror(errno) << ")") +#undef LOG4CXX_DEBUG +#define LOG4CXX_DEBUG(loggerPtr, logEvent) \ + LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getDebug(), logEvent) -#else // ENABLE_LOG is OFF +#undef LOG4CXX_INFO +#define LOG4CXX_INFO(loggerPtr, logEvent) \ + LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getInfo(), logEvent) - #define CREATE_LOGGERPTR_GLOBAL(logger_var, logger_name) +#undef LOG4CXX_WARN +#define LOG4CXX_WARN(loggerPtr, logEvent) \ + LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getWarn(), logEvent) - #define CREATE_LOGGERPTR_LOCAL(logger_var, logger_name) +#undef LOG4CXX_ERROR +#define LOG4CXX_ERROR(loggerPtr, logEvent) \ + LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getError(), logEvent) - #define INIT_LOGGER(file_name) +#undef LOG4CXX_FATAL +#define LOG4CXX_FATAL(loggerPtr, logEvent) \ + LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getFatal(), logEvent) - #define DEINIT_LOGGER(file_name) +#define LOG4CXX_ERROR_WITH_ERRNO(loggerPtr, message) \ + LOG4CXX_ERROR(loggerPtr, \ + message << ", error code " << errno << " (" << strerror(errno) \ + << ")") - #define LOG4CXX_IS_TRACE_ENABLED(logger) false +#define LOG4CXX_WARN_WITH_ERRNO(loggerPtr, message) \ + LOG4CXX_WARN(loggerPtr, \ + message << ", error code " << errno << " (" << strerror(errno) \ + << ")") - #undef LOG4CXX_INFO - #define LOG4CXX_INFO(x,y) +#else // ENABLE_LOG is OFF - #undef LOG4CXX_WARN - #define LOG4CXX_WARN(x,y) +#define CREATE_LOGGERPTR_GLOBAL(logger_var, logger_name) - #undef LOG4CXX_ERROR - #define LOG4CXX_ERROR(x,y) +#define CREATE_LOGGERPTR_LOCAL(logger_var, logger_name) - #undef LOG4CXX_ERROR_WITH_ERRNO - #define LOG4CXX_ERROR_WITH_ERRNO(x,y) +#define INIT_LOGGER(file_name) - #undef LOG4CXX_WARN_WITH_ERRNO - #define LOG4CXX_WARN_WITH_ERRNO(x,y) +#define DEINIT_LOGGER(file_name) - #undef LOG4CXX_TRACE - #define LOG4CXX_TRACE(x,y) +#define LOG4CXX_IS_TRACE_ENABLED(logger) false - #undef LOG4CXX_DEBUG - #define LOG4CXX_DEBUG(x,y) +#undef LOG4CXX_TRACE +#define LOG4CXX_TRACE(x, y) - #undef LOG4CXX_FATAL - #define LOG4CXX_FATAL(x,y) +#define LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, auto_trace) +#define LOG4CXX_AUTO_TRACE(loggerPtr) - #define LOG4CXX_INFO_EXT(logger, logEvent) - #define LOG4CXX_INFO_STR_EXT(logger, logEvent) +#undef LOG4CXX_DEBUG +#define LOG4CXX_DEBUG(x, y) - #define LOG4CXX_TRACE_EXT(logger, logEvent) - #define LOG4CXX_TRACE_STR_EXT(logger, logEvent) +#undef LOG4CXX_INFO +#define LOG4CXX_INFO(x, y) - #define LOG4CXX_DEBUG_EXT(logger, logEvent) - #define LOG4CXX_DEBUG_STR_EXT(logger, logEvent) +#undef LOG4CXX_WARN +#define LOG4CXX_WARN(x, y) - #define LOG4CXX_WARN_EXT(logger, logEvent) - #define LOG4CXX_WARN_STR_EXT(logger, logEvent) +#undef LOG4CXX_ERROR +#define LOG4CXX_ERROR(x, y) - #define LOG4CXX_ERROR_EXT(logger, logEvent) - #define LOG4CXX_ERROR_STR_EXT(logger, logEvent) +#undef LOG4CXX_ERROR_WITH_ERRNO +#define LOG4CXX_ERROR_WITH_ERRNO(x, y) - #define LOG4CXX_FATAL_EXT(logger, logEvent) - #define LOG4CXX_FATAL_STR_EXT(logger, logEvent) +#undef LOG4CXX_WARN_WITH_ERRNO +#define LOG4CXX_WARN_WITH_ERRNO(x, y) - #define LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, auto_trace) - #define LOG4CXX_AUTO_TRACE(loggerPtr) +#undef LOG4CXX_FATAL +#define LOG4CXX_FATAL(x, y) #endif // ENABLE_LOG -#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_ +#endif // SRC_COMPONENTS_INCLUDE_UTILS_LOGGER_H_ diff --git a/src/components/include/utils/macro.h b/src/components/include/utils/macro.h index bfd13411f4..0e029e4b06 100644 --- a/src/components/include/utils/macro.h +++ b/src/components/include/utils/macro.h @@ -39,8 +39,8 @@ #endif #include "logger.h" - - +// A macro to set some action for variable to avoid "unused variable" warning +#define UNUSED(x) (void) x; // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ @@ -59,51 +59,60 @@ friend utils::deleters::Deleter<TypeName>::~Deleter() #ifdef DEBUG - #define ASSERT(condition) \ - do { \ - DEINIT_LOGGER(); \ - assert(condition); \ - } while (false) +#define ASSERT(condition) \ + FLUSH_LOGGER(); \ + 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__) +#define ASSERT(condition) \ + fprintf(stderr, \ + "Failed condition \"" #condition "\" [%s:%d][%s]\n\n", \ + __FILE__, \ + __LINE__, \ + __FUNCTION__) #endif -#define DCHECK(condition) \ - if (!(condition)) { \ - CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \ - LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \ - << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']'); \ - ASSERT((condition)); \ +#define DCHECK(condition) \ + if (!(condition)) { \ + CREATE_LOGGERPTR_LOCAL(logger_, "Utils"); \ + 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); \ +#define DCHECK_OR_RETURN(condition, return_value) \ + if (!(condition)) { \ + CREATE_LOGGERPTR_LOCAL(logger_, "Utils"); \ + 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 DCHECK_OR_RETURN_VOID(condition) \ + if (!(condition)) { \ + CREATE_LOGGERPTR_LOCAL(logger_, "Utils"); \ + LOG4CXX_FATAL(logger_, \ + "DCHECK failed with \"" << #condition << "\" [" \ + << __FUNCTION__ << "][" << __FILE__ \ + << ':' << __LINE__ << ']'); \ + ASSERT((condition)); \ + return; \ } - #define NOTREACHED() DCHECK(!"Unreachable code") // Allows to perform static check that virtual function from base class is @@ -120,11 +129,11 @@ * @brief Calculate size of na array * @param arr array, which size need to calculate */ -#define ARRAYSIZE(arr) sizeof (arr) / sizeof(*arr) +#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 +#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/make_shared.h b/src/components/include/utils/make_shared.h index dc817e362d..9d40d646a6 100644 --- a/src/components/include/utils/make_shared.h +++ b/src/components/include/utils/make_shared.h @@ -48,61 +48,144 @@ * SharedPtr<A> shared2(MakeShared<A>(5, 5.5); * SharedPtr<A> shared3(MakeShared<A>(5, 5.5, std::string("MyStr")); * - * The profit in using MakeShared instead of simple allocation with operator new is evident. - * Firstly it allows us to centralize allocation place, secondly it allows us to use + * The profit in using MakeShared instead of simple allocation with operator new + *is evident. + * Firstly it allows us to centralize allocation place, secondly it allows us to + *use * safe operator new overloading (no throwable one). */ namespace utils { -template <typename T> class SharedPtr; +template <typename T> +class SharedPtr; namespace { template <typename T> - SharedPtr<T>Initialize(T* object) { - return object == NULL ? SharedPtr<T>() : SharedPtr<T>(object); - } +SharedPtr<T> Initialize(T* object) { + return object == NULL ? SharedPtr<T>() : SharedPtr<T>(object); +} } -template<typename T> +template <typename T> SharedPtr<T> MakeShared() { T* t = new (std::nothrow) T; return Initialize(t); } -template<typename T, typename Arg1> +template <typename T, typename Arg1> +SharedPtr<T> MakeShared(Arg1& arg1) { + T* t = new (std::nothrow) T(arg1); + return Initialize(t); +} + +template <typename T, typename Arg1, typename Arg2> +SharedPtr<T> MakeShared(Arg1& arg1, Arg2& arg2) { + T* t = new (std::nothrow) T(arg1, arg2); + return Initialize(t); +} + +template <typename T, typename Arg1, typename Arg2, typename Arg3> +SharedPtr<T> MakeShared(Arg1& arg1, Arg2& arg2, Arg3& arg3) { + T* t = new (std::nothrow) T(arg1, arg2, arg3); + return Initialize(t); +} + +template <typename T, + typename Arg1, + typename Arg2, + typename Arg3, + typename Arg4> +SharedPtr<T> MakeShared(Arg1& arg1, Arg2& arg2, Arg3& arg3, Arg4& arg4) { + T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4); + return Initialize(t); +} + +template <typename T, + typename Arg1, + typename Arg2, + typename Arg3, + typename Arg4, + typename Arg5> +SharedPtr<T> MakeShared( + Arg1& arg1, Arg2& arg2, Arg3& arg3, Arg4& arg4, Arg5& arg5) { + T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4, arg5); + return Initialize(t); +} + +template <typename T, + typename Arg1, + typename Arg2, + typename Arg3, + typename Arg4, + typename Arg5, + typename Arg6> +SharedPtr<T> MakeShared( + Arg1& arg1, Arg2& arg2, Arg3& arg3, Arg4& arg4, Arg5& arg5, Arg6& arg6) { + T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4, arg5, arg6); + return Initialize(t); +} + +template <typename T, typename Arg1> SharedPtr<T> MakeShared(const Arg1& arg1) { - T* t = new (std::nothrow) T(arg1); - return Initialize(t); + T* t = new (std::nothrow) T(arg1); + return Initialize(t); } -template<typename T, typename Arg1, typename Arg2> +template <typename T, typename Arg1, typename Arg2> SharedPtr<T> MakeShared(const Arg1& arg1, const Arg2& arg2) { - T* t = new (std::nothrow) T(arg1, arg2); - return Initialize(t); + T* t = new (std::nothrow) T(arg1, arg2); + return Initialize(t); } -template<typename T, typename Arg1, typename Arg2, typename Arg3> +template <typename T, typename Arg1, typename Arg2, typename Arg3> SharedPtr<T> MakeShared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { - T* t = new (std::nothrow) T(arg1, arg2, arg3); - return Initialize(t); + T* t = new (std::nothrow) T(arg1, arg2, arg3); + return Initialize(t); } -template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> -SharedPtr<T> MakeShared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) { - T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4); - return Initialize(t); +template <typename T, + typename Arg1, + typename Arg2, + typename Arg3, + typename Arg4> +SharedPtr<T> MakeShared(const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4) { + T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4); + return Initialize(t); } -template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> -SharedPtr<T> MakeShared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) { - T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4, arg5); - return Initialize(t); +template <typename T, + typename Arg1, + typename Arg2, + typename Arg3, + typename Arg4, + typename Arg5> +SharedPtr<T> MakeShared(const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5) { + T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4, arg5); + return Initialize(t); } -template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> -SharedPtr<T> MakeShared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, const Arg6& arg6) { - T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4, arg5, arg6); - return Initialize(t); +template <typename T, + typename Arg1, + typename Arg2, + typename Arg3, + typename Arg4, + typename Arg5, + typename Arg6> +SharedPtr<T> MakeShared(const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6) { + T* t = new (std::nothrow) T(arg1, arg2, arg3, arg4, arg5, arg6); + return Initialize(t); } -} // namespace utils; -#endif // SRC_COMPONENTS_INCLUDE_UTILS_MAKE_SHARED_H_ +} // namespace utils; +#endif // SRC_COMPONENTS_INCLUDE_UTILS_MAKE_SHARED_H_ diff --git a/src/components/include/utils/message_queue.h b/src/components/include/utils/message_queue.h index e0b3336728..093aa4cac2 100644 --- a/src/components/include/utils/message_queue.h +++ b/src/components/include/utils/message_queue.h @@ -34,10 +34,10 @@ #define SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_ #include <queue> +#include <algorithm> #include "utils/conditional_variable.h" #include "utils/lock.h" -#include "utils/logger.h" #include "utils/prioritized_queue.h" /** @@ -47,151 +47,171 @@ namespace utils { -template<typename T, class Q = std::queue<T> > class MessageQueue { - public: - typedef Q Queue; - /** - * \brief Default constructor - */ - MessageQueue(); - - /** - * \brief Destructor - */ - ~MessageQueue(); - - /** - * \brief Returns size of the queue. - * \return Size of the queue. - */ - size_t size() const; - - /** - * \brief If queue is empty. - * \return Is queue empty. - */ - bool empty() const; - - /** - * \brief Tells if queue is being shut down - */ - bool IsShuttingDown() const; - - /** - * \brief Adds element to the queue. - * \param element Element to be added to the queue.n - */ - void push(const T& element); - - /** - * \brief Removes element from the queue and returns it. - * \return To element of the queue. - */ - T pop(); - - /** - * \brief Conditional wait. - */ - void wait(); - - /** - * \brief Shutdown the queue. - * This leads to waking up everyone waiting on the queue - * Queue being shut down can be drained ( with pop() ) - * But nothing must be added to the queue after it began - * shutting down - */ - void Shutdown(); - - /** - * \brief Clears queue. - */ - void Reset(); - - private: - /** - *\brief Queue - */ - Queue queue_; - volatile bool shutting_down_; - - /** - *\brief Platform specific syncronisation variable - */ - mutable sync_primitives::Lock queue_lock_; - sync_primitives::ConditionalVariable queue_new_items_; +template <typename T, class Q = std::queue<T> > +class MessageQueue { + public: + typedef Q Queue; + /** + * \brief Default constructor + */ + MessageQueue(); + + /** + * \brief Destructor + */ + ~MessageQueue(); + + /** + * \brief Returns size of the queue. + * \return Size of the queue. + */ + size_t size() const; + + /** + * \brief If queue is empty. + * \return Is queue empty. + */ + bool empty() const; + + /** + * \brief Tells if queue is being shut down + */ + bool IsShuttingDown() const; + + /** + * \brief Adds element to the queue. + * \param element Element to be added to the queue.n + */ + void push(const T& element); + + /** + * \brief Removes element from the queue and returns it + * \param element Element to be returned + * \return True on success, false if queue is empty + */ + bool pop(T& element); + + /** + * \brief Conditional wait. + */ + void wait(); + + /** + * \brief waitUntilEmpty message queue + * Wait until message queue is empty + */ + void WaitUntilEmpty(); + + /** + * \brief Shutdown the queue. + * This leads to waking up everyone waiting on the queue + * Queue being shut down can be drained ( with pop() ) + * But nothing must be added to the queue after it began + * shutting down + */ + void Shutdown(); + + /** + * \brief Clears queue. + */ + void Reset(); + + private: + /** + *\brief Queue + */ + Queue queue_; + volatile bool shutting_down_; + + /** + *\brief Platform specific syncronisation variable + */ + mutable sync_primitives::Lock queue_lock_; + sync_primitives::ConditionalVariable queue_new_items_; }; -template<typename T, class Q> MessageQueue<T, Q>::MessageQueue() - : shutting_down_(false) { -} +template <typename T, class Q> +MessageQueue<T, Q>::MessageQueue() + : shutting_down_(false) {} -template<typename T, class Q> MessageQueue<T, Q>::~MessageQueue() { - if (!queue_.empty()) { - CREATE_LOGGERPTR_LOCAL(logger_, "Utils") - LOG4CXX_ERROR(logger_, "Destruction of non-drained queue"); +template <typename T, class Q> +MessageQueue<T, Q>::~MessageQueue() {} + +template <typename T, class Q> +void MessageQueue<T, Q>::wait() { + sync_primitives::AutoLock auto_lock(queue_lock_); + while ((!shutting_down_) && queue_.empty()) { + queue_new_items_.Wait(auto_lock); } } -template<typename T, class Q> void MessageQueue<T, Q>::wait() { +template <typename T, class Q> +void MessageQueue<T, Q>::WaitUntilEmpty() { sync_primitives::AutoLock auto_lock(queue_lock_); - while ((!shutting_down_) && queue_.empty()) { + while ((!shutting_down_) && !queue_.empty()) { queue_new_items_.Wait(auto_lock); } } -template<typename T, class Q> size_t MessageQueue<T, Q>::size() const { +template <typename T, class Q> +size_t MessageQueue<T, Q>::size() const { sync_primitives::AutoLock auto_lock(queue_lock_); return queue_.size(); } -template<typename T, class Q> bool MessageQueue<T, Q>::empty() const { +template <typename T, class Q> +bool MessageQueue<T, Q>::empty() const { sync_primitives::AutoLock auto_lock(queue_lock_); return queue_.empty(); } -template<typename T, class Q> bool MessageQueue<T, Q>::IsShuttingDown() const { +template <typename T, class Q> +bool MessageQueue<T, Q>::IsShuttingDown() const { return shutting_down_; } -template<typename T, class Q> void MessageQueue<T, Q>::push(const T& element) { +template <typename T, class Q> +void MessageQueue<T, Q>::push(const T& element) { { sync_primitives::AutoLock auto_lock(queue_lock_); if (shutting_down_) { - CREATE_LOGGERPTR_LOCAL(logger_, "Utils") - LOG4CXX_ERROR(logger_, "Runtime error, pushing into queue" - " that is being shut down"); - return; + return; } - queue_.push(element); + queue_.push(element); } queue_new_items_.Broadcast(); } -template<typename T, class Q> T MessageQueue<T, Q>::pop() { +template <typename T, class Q> +bool MessageQueue<T, Q>::pop(T& element) { sync_primitives::AutoLock auto_lock(queue_lock_); if (queue_.empty()) { - CREATE_LOGGERPTR_LOCAL(logger_, "Utils") - LOG4CXX_ERROR(logger_, "Runtime error, popping out of empty queue"); - NOTREACHED(); + return false; } - T result = queue_.front(); + element = queue_.front(); queue_.pop(); - return result; + queue_new_items_.NotifyOne(); + return true; } -template<typename T, class Q> void MessageQueue<T, Q>::Shutdown() { +template <typename T, class Q> +void MessageQueue<T, Q>::Shutdown() { sync_primitives::AutoLock auto_lock(queue_lock_); shutting_down_ = true; + if (!queue_.empty()) { + Queue empty_queue; + std::swap(queue_, empty_queue); + } queue_new_items_.Broadcast(); } -template<typename T, class Q> void MessageQueue<T, Q>::Reset() { +template <typename T, class Q> +void MessageQueue<T, Q>::Reset() { sync_primitives::AutoLock auto_lock(queue_lock_); shutting_down_ = false; if (!queue_.empty()) { Queue empty_queue; - queue_.swap(empty_queue); + std::swap(queue_, empty_queue); } } diff --git a/src/components/include/utils/messagemeter.h b/src/components/include/utils/messagemeter.h index a5d9968d81..42b658ad6b 100644 --- a/src/components/include/utils/messagemeter.h +++ b/src/components/include/utils/messagemeter.h @@ -94,7 +94,7 @@ class MessageMeter { template <class Id> MessageMeter<Id>::MessageMeter() - : time_range_(TimevalStruct {0, 0}) { + : time_range_(TimevalStruct{0, 0}) { time_range_.tv_sec = 1; } @@ -104,8 +104,7 @@ size_t MessageMeter<Id>::TrackMessage(const Id& id) { } template <class Id> -size_t MessageMeter<Id>::TrackMessages(const Id& id, - const size_t count) { +size_t MessageMeter<Id>::TrackMessages(const Id& id, const size_t count) { Timings& timings = timing_map_[id]; const TimevalStruct current_time = date_time::DateTime::getCurrentTime(); for (size_t i = 0; i < count; ++i) { @@ -118,18 +117,16 @@ size_t MessageMeter<Id>::TrackMessages(const Id& id, template <class Id> size_t MessageMeter<Id>::Frequency(const Id& id) { typename TimingMap::iterator it = timing_map_.find(id); - if(it == timing_map_.end()) { + if (it == timing_map_.end()) { return 0u; } Timings& timings = it->second; if (timings.empty()) { return 0u; } - const TimevalStruct actual_begin_time = - date_time::DateTime::Sub(date_time::DateTime::getCurrentTime(), - time_range_); - timings.erase(timings.begin(), - timings.upper_bound(actual_begin_time)); + const TimevalStruct actual_begin_time = date_time::DateTime::Sub( + date_time::DateTime::getCurrentTime(), time_range_); + timings.erase(timings.begin(), timings.upper_bound(actual_begin_time)); return timings.size(); } @@ -152,7 +149,7 @@ void MessageMeter<Id>::set_time_range(const size_t time_range_msecs) { const size_t mSecs = time_range_msecs % date_time::DateTime::MILLISECONDS_IN_SECOND; time_range_.tv_usec = - mSecs * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + mSecs * date_time::DateTime::MICROSECONDS_IN_MILLISECOND; } template <class Id> void MessageMeter<Id>::set_time_range(const TimevalStruct& time_range) { diff --git a/src/components/include/utils/prioritized_queue.h b/src/components/include/utils/prioritized_queue.h index 2a8ebf0a7b..eb4ba6a6c3 100644 --- a/src/components/include/utils/prioritized_queue.h +++ b/src/components/include/utils/prioritized_queue.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 @@ -30,12 +30,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_PRIORITIZED_QUEUE_H_ -#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_PRIORITIZED_QUEUE_H_ +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_PRIORITIZED_QUEUE_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_PRIORITIZED_QUEUE_H_ #include <queue> #include <map> -#include <iostream> +#include <algorithm> #include "utils/macro.h" @@ -45,15 +45,13 @@ namespace utils { * Template queue class that gives out messages respecting their priority * Message class must have size_t PriorityOrder() method implemented */ -template < typename M > +template <typename M> class PrioritizedQueue { public: typedef M value_type; // std::map guarantees it's contents is sorted by key typedef std::map<size_t, std::queue<value_type> > QueuesMap; - PrioritizedQueue() - : total_size_(0) { - } + PrioritizedQueue() : total_size_(0) {} // All api mimics usual std queue interface void push(const value_type& message) { size_t message_priority = message.PriorityOrder(); @@ -66,6 +64,10 @@ class PrioritizedQueue { bool empty() const { return queues_.empty(); } + void swap(PrioritizedQueue<M>& x) { + std::swap(queues_, x.queues_); + std::swap(total_size_, x.total_size_); + } value_type front() { DCHECK(!queues_.empty() && !queues_.rbegin()->second.empty()); return queues_.rbegin()->second.front(); @@ -79,11 +81,12 @@ class PrioritizedQueue { queues_.erase(last); } } + private: QueuesMap queues_; size_t total_size_; }; -} +} // namespace utils -#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_ +#endif // SRC_COMPONENTS_INCLUDE_UTILS_PRIORITIZED_QUEUE_H_ diff --git a/src/components/include/utils/push_log.h b/src/components/include/utils/push_log.h index 01389fb736..aaeaa83bae 100644 --- a/src/components/include/utils/push_log.h +++ b/src/components/include/utils/push_log.h @@ -38,15 +38,20 @@ namespace logger { -bool push_log( - log4cxx::LoggerPtr logger, - log4cxx::LevelPtr level, - const std::string& entry, - log4cxx_time_t timeStamp, - const log4cxx::spi::LocationInfo& location, - const log4cxx::LogString& threadName - ); +bool push_log(log4cxx::LoggerPtr logger, + log4cxx::LevelPtr level, + const std::string& entry, + log4cxx_time_t timeStamp, + const log4cxx::spi::LocationInfo& location, + const log4cxx::LogString& threadName); +void flush_logger(); + +bool logs_enabled(); +void set_logs_enabled(bool state); + +void create_log_message_loop_thread(); +void delete_log_message_loop_thread(); } // namespace logger #endif // SRC_COMPONENTS_INCLUDE_UTILS_PUSH_LOG_H_ diff --git a/src/components/include/utils/rwlock.h b/src/components/include/utils/rwlock.h index 1083dbd63f..b7e7484b48 100644 --- a/src/components/include/utils/rwlock.h +++ b/src/components/include/utils/rwlock.h @@ -51,10 +51,13 @@ typedef pthread_rwlock_t PlatformRWLock; /** * 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. + * 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. + * An exclusive write lock is not permitted until all read locks have been + * released. */ class RWLock { @@ -67,14 +70,19 @@ class RWLock { * 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. + * 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. + * (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). + * 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(); @@ -91,9 +99,12 @@ class RWLock { /** * @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" + * 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(); @@ -101,11 +112,13 @@ class RWLock { /** * @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) + * 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) + * 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 @@ -132,8 +145,7 @@ class RWLock { class AutoReadLock { public: - explicit AutoReadLock(RWLock& rwlock) - : rwlock_(rwlock) { + explicit AutoReadLock(RWLock& rwlock) : rwlock_(rwlock) { rwlock_.AcquireForReading(); } ~AutoReadLock() { @@ -147,12 +159,12 @@ class AutoReadLock { /** * @brief Makes auto lock read-write locks for writing - * Please use AutoWriteLock to acquire for writing and (automatically) release it + * 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() { diff --git a/src/components/include/utils/scope_guard.h b/src/components/include/utils/scope_guard.h new file mode 100644 index 0000000000..bc60a7d288 --- /dev/null +++ b/src/components/include/utils/scope_guard.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2015, 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_SCOPE_GUARD_H +#define SRC_COMPONENTS_INCLUDE_UTILS_SCOPE_GUARD_H + +namespace utils { + +/** + * @brief The ScopeGuardImplBase class the class which allows to keep safety + * raw pointer within local scope. The same ScopeGuard has been provided by + * Andrej Alexandresku in the Loki library. + * + * The usage area example: + * + * Suppose user have to create some pointer in function call Init(). And in case + * of some fail condition this pointer has to be freed. So in order to avoid + * code duplicate as follows: + * + * bool SomeClass::Init() { + * memberObject_ = custom_allocate() // initialize member object with some + *value + * if(!some_condition) { + * custom_release(memberObject(); + * return false; + * } + * + * if(!other_condition) { + * custom_release(memberObject) + * return false; + * } + * return true; + * } + * + * The user is able to use ScopeGuard, where possible to automatically call + * custom release function. See example bellow: + * + * bool SomeClass::Init() { + * memberObject_ = custom_allocate() // initialize member object with some + *value + * // The guard will call custom release function when it goes out of scope. + * ScopeGaurd guard = MakeGuard(custom_release, memberObject); + * if(!some_condition) { + * return false; + * } + * + * if(!other_condition) { + * return false; + * } + * // Here to avoid object releasing the user has to call Dismiss method. + * // So no custom release function will be called after return statement. + * guard.Dismiss(); + * return true; + * } + */ +class ScopeGuardImplBase { + public: + /** + * @brief ScopeGuardImplBase the ScopeGuards constructor. + */ + ScopeGuardImplBase() : dismissed_(false) {} + + /** + * @brief Dismiss function which allows to dismiss releasing of stored object. + */ + void Dismiss() const { + dismissed_ = true; + } + + protected: + /** + * @brief ScopeGuardImplBase the copy constructor + * + * @param other the object that should be copied. + */ + ScopeGuardImplBase(const ScopeGuardImplBase& other) + : dismissed_(other.dismissed_) { + other.Dismiss(); + } + + /** + * Allows to safely execute release function(i.e. it will be called only + * in case of releasing wasn't dismiss.) + */ + template <typename T> + void SafeExecute(T& t) { + if (!t.dismissed_) { + t.Execute(); + } + } + + ~ScopeGuardImplBase() {} + + mutable bool dismissed_; + + private: + // Disallow copying via assign operator. + ScopeGuardImplBase& operator=(const ScopeGuardImplBase&); +}; + +/** + * The class which allows to bind some parameter with free function. + * I.E. + * void release(char* p){delete p;} + * + * ScopeGuard guard = MakeGuard(release, p); + * + * So the parameter p will be passed to the specified function. + */ +template <typename Function, typename Parameter1> +class ScopeGuardImpl1 : public ScopeGuardImplBase { + public: + /** + * @brief MakeGuard allows to create ScopeGuard object. + * + * @param fun function to call, when out of scope. + * + * @param p1 parameter which will be passed to the certain function. + * + * @return ScopeGuard object. + */ + static ScopeGuardImpl1<Function, Parameter1> MakeGuard(Function fun, + const Parameter1& p1) { + return ScopeGuardImpl1<Function, Parameter1>(fun, p1); + } + + /** + Execute the SafeExecute function in destructor. + */ + ~ScopeGuardImpl1() { + SafeExecute(*this); + } + + protected: + /** + * @brief Execute allows to execute certain function with certain parameter. + */ + void Execute() { + fun_(p1_); + } + + /** + * @brief ScopeGuardImpl1 create ScopeGuard object. + * + * @param f function object. + * + * @param p1 parameter to to pass to the function object. + */ + ScopeGuardImpl1(const Function& f, const Parameter1& p1) : fun_(f), p1_(p1) {} + + private: + Function fun_; + const Parameter1 p1_; + + friend class ScopeGuardImplBase; +}; + +/** + * The class which allows to call some member function in case of + * ScopeGuard object out of scope. + * I.E. + * vector<int> vec; + * + * // When function returns, the pop_back method for vector will be called. + * void foo() { + * ScopeGuard guard = MakeObjGuard(vec, &vector::pop_back); + * vec.push_back(5); + * } + */ +template <typename Obj, typename MemFun> +class ObjScopeGuardImpl0 : public ScopeGuardImplBase { + public: + /** + * @brief MakeObjGuard creates ScopeGuard object. + * + * @param obj object whose method will be called. + * + * @param memFun the method to call. + * + * @return ScopeGuard object. + */ + static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) { + return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun); + } + + /** + Execute the SafeExecute function in destructor. + */ + ~ObjScopeGuardImpl0() { + SafeExecute(*this); + } + + protected: + /** + * @brief Execute allows to execute certain function with certain parameter. + */ + void Execute() { + (obj_.*memFun_)(); + } + + /** + * @brief ObjScopeGuardImpl0 Create ScopeGuard object. + * + * @param obj object whose method will be called. + * + * @param memFun the method to call. + * + * @return ScopeGuard object. + */ + ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun) {} + + private: + Obj& obj_; + MemFun memFun_; + friend class ScopeGuardImplBase; +}; + +/** + * The class which allows to call some member function with certain parameter + * in case of ScopeGuard object out of scope. + + */ +template <typename Obj, typename MemFun, typename Parameter1> +class ObjScopeGuardImpl1 : public ScopeGuardImplBase { + public: + /** + * @brief MakeObjGuard creates ScopeGuard object. + * + * @param obj object whose method will be called. + * + * @param memFun the method to call. + * + * @param p1 the parameter to pass to the member function. + * + * @return ScopeGuard object. + */ + static ObjScopeGuardImpl1<Obj, MemFun, Parameter1> MakeObjGuard( + Obj& obj, MemFun memFun, const Parameter1& p1) { + return ObjScopeGuardImpl1<Obj, MemFun, Parameter1>(obj, memFun, p1); + } + + /** + Execute the SafeExecute function in destructor. + */ + ~ObjScopeGuardImpl1() { + SafeExecute(*this); + } + + protected: + /** + * @brief Execute allows to execute certain function with certain parameter. + */ + void Execute() { + (obj_.*memFun_)(p1_); + } + + /** + * @brief MakeObjGuard creates ScopeGuard object. + * + * @param obj object whose method will be called. + * + * @param memFun the method to call. + * + * @param p1 the parameter to pass to the member function. + * + * @return ScopeGuard object. + */ + ObjScopeGuardImpl1(Obj& obj, MemFun memFun, const Parameter1& p1) + : obj_(obj), memFun_(memFun), p1_(p1) {} + + private: + Obj& obj_; + MemFun memFun_; + const Parameter1 p1_; + friend class ScopeGuardImplBase; +}; + +typedef const ScopeGuardImplBase& ScopeGuard; + +template <typename F, typename P1> +ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) { + return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1); +} + +template <typename Obj, typename MemFun> +ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) { + return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun); +} + +template <typename Obj, typename MemFun, typename P1> +ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, + MemFun memFun, + const P1& p1) { + return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1); +} +} +#endif // SRC_COMPONENTS_INCLUDE_UTILS_SCOPE_GUARD_H diff --git a/src/components/include/utils/shared_ptr.h b/src/components/include/utils/shared_ptr.h index f506c6018e..064bb36b4a 100644 --- a/src/components/include/utils/shared_ptr.h +++ b/src/components/include/utils/shared_ptr.h @@ -41,6 +41,7 @@ #include "utils/atomic.h" namespace utils { + /** * @brief Shared pointer. * @@ -50,215 +51,228 @@ namespace utils { * * @tparam ObjectType Type of wrapped object. **/ -template<typename ObjectType> +template <typename ObjectType> class SharedPtr { - public: - //std smart pointer compability - typedef ObjectType element_type; - /** - * @brief Constructor. - * - * Initialize shared pointer with wrapped object. - * Reference counter will be initialized to 1. - * - * @param Object Wrapped object. - **/ - SharedPtr(ObjectType* Object); - - SharedPtr(); - - /** - * @brief Copy constructor. - * - * Initialize shared pointer with another shared pointer. - * Reference counter will be incremented. - * - * @param Other Other shared pointer. - **/ - SharedPtr(const SharedPtr<ObjectType>& Other); - - /** - * @brief Copy constructor. - * - * Initialize shared pointer with another shared pointer. - * Reference counter will be incremented. - * - * @tparam OtherObjectType Type of other object pointer. This - * allows creating a shared pointer to an - * intstance of a base class from a shared - * pointer to an instance of a class - * inherited from this base class. - * If OtherObjectType is not implicitly - * convertible to ObjectType it will - * cause a compile error. - * - * @param Other Other shared pointer. - **/ - template<typename OtherObjectType> - SharedPtr(const SharedPtr<OtherObjectType>& Other); - - /** - * @brief Destructor. - * - * Decrement reference counter and destroy wrapped object - * if reference counter reaches zero. - **/ - ~SharedPtr(); - - /** - * @brief Assignment operator. - * - * Drop reference to currently referenced object and add - * reference to assigned object. - * - * @param Other Shared pointer to an object - * that must be referenced. - * - * @return Reference to this shared pointer. - **/ - SharedPtr<ObjectType>& operator =(const SharedPtr<ObjectType>& Other); - - bool operator ==(const SharedPtr<ObjectType>& Other) const; - - bool operator< (const SharedPtr<ObjectType>& other) const; - - /** - * @brief Assignment operator. - * - * Drop reference to currently referenced object and add - * reference to assigned object. - * - * @tparam OtherObjectType Type of other object pointer. This - * allows creating a shared pointer to an - * intstance of a base class from a shared - * pointer to an instance of a class - * inherited from this base class. - * If OtherObjectType is not implicitly - * convertible to ObjectType it will - * cause a compile error. - * - * @param Other Shared pointer to an object - * that must be referenced. - * - * @return Reference to this shared pointer. - **/ - template<typename OtherObjectType> - SharedPtr<ObjectType>& operator =(const SharedPtr<OtherObjectType>& Other); - - template<typename OtherObjectType> - static SharedPtr<OtherObjectType> static_pointer_cast( + static void DummyDeleter(ObjectType* object_to_delete) { + delete object_to_delete; + } + + public: + // std smart pointer compatibility + typedef ObjectType element_type; + typedef void (*Deleter)(ObjectType*); + /** + * @brief Constructor. + * + * Initialize shared pointer with wrapped object. + * Reference counter will be initialized to 1. + * + * @param Object Wrapped object. + **/ + SharedPtr(ObjectType* Object); + + SharedPtr(ObjectType* Object, Deleter deleter) + : mObject(Object) + , mReferenceCounter(new uint32_t(1)) + , deleter_(deleter) {} + + SharedPtr(); + + /** + * @brief Copy constructor. + * + * Initialize shared pointer with another shared pointer. + * Reference counter will be incremented. + * + * @param Other Other shared pointer. + **/ + SharedPtr(const SharedPtr<ObjectType>& Other); + + /** + * @brief Copy constructor. + * + * Initialize shared pointer with another shared pointer. + * Reference counter will be incremented. + * + * @tparam OtherObjectType Type of other object pointer. This + * allows creating a shared pointer to an + * intstance of a base class from a shared + * pointer to an instance of a class + * inherited from this base class. + * If OtherObjectType is not implicitly + * convertible to ObjectType it will + * cause a compile error. + * + * @param Other Other shared pointer. + **/ + template <typename OtherObjectType> + SharedPtr(const SharedPtr<OtherObjectType>& Other); + + /** + * @brief Destructor. + * + * Decrement reference counter and destroy wrapped object + * if reference counter reaches zero. + **/ + ~SharedPtr(); + + /** + * @brief Assignment operator. + * + * Drop reference to currently referenced object and add + * reference to assigned object. + * + * @param Other Shared pointer to an object + * that must be referenced. + * + * @return Reference to this shared pointer. + **/ + SharedPtr<ObjectType>& operator=(const SharedPtr<ObjectType>& Other); + + bool operator==(const SharedPtr<ObjectType>& Other) const; + + bool operator<(const SharedPtr<ObjectType>& other) const; + + /** + * @brief Assignment operator. + * + * Drop reference to currently referenced object and add + * reference to assigned object. + * + * @tparam OtherObjectType Type of other object pointer. This + * allows creating a shared pointer to an + * intstance of a base class from a shared + * pointer to an instance of a class + * inherited from this base class. + * If OtherObjectType is not implicitly + * convertible to ObjectType it will + * cause a compile error. + * + * @param Other Shared pointer to an object + * that must be referenced. + * + * @return Reference to this shared pointer. + **/ + template <typename OtherObjectType> + SharedPtr<ObjectType>& operator=(const SharedPtr<OtherObjectType>& Other); + + template <typename OtherObjectType> + static SharedPtr<OtherObjectType> static_pointer_cast( const SharedPtr<ObjectType>& pointer); - template<typename OtherObjectType> - static SharedPtr<OtherObjectType> dynamic_pointer_cast( + template <typename OtherObjectType> + static SharedPtr<OtherObjectType> dynamic_pointer_cast( const SharedPtr<ObjectType>& pointer); - /** - * @brief Member access operator. - * - * @return Wrapped object. - **/ - ObjectType* operator->() const; - - ObjectType& operator*() const; - operator bool() const; - void reset(); - void reset(ObjectType* other); - ObjectType* get() const; - - /** - * @return true if mObject not NULL - */ - bool valid() const; - - private: - void reset_impl(ObjectType* other); - - // TSharedPtr needs access to other TSharedPtr private members - // for shared pointers type casts. - template<typename OtherObjectType> - friend class SharedPtr; - - /** - * @brief Drop reference to wrapped object. - * - * If reference counter reaches zero object and its reference - * counter will be deallocated. - **/ - void dropReference(); - - /** - * @brief Wrapped object. - **/ - ObjectType* mObject; - - /** - * @brief Pointer to reference counter. - **/ - uint32_t* mReferenceCounter; - - void release(); + /** + * @brief Member access operator. + * + * @return Wrapped object. + **/ + ObjectType* operator->() const; + + ObjectType& operator*() const; + operator bool() const; + void reset(); + void reset(ObjectType* other); + ObjectType* get() const; + +#ifdef BUILD_TESTS + inline const uint32_t* get_ReferenceCounter() const { + return mReferenceCounter; + } +#endif // BUILD_TESTS + + /** + * @return true if mObject not NULL + */ + bool valid() const; + + private: + void reset_impl(ObjectType* other); + + // TSharedPtr needs access to other TSharedPtr private members + // for shared pointers type casts. + template <typename OtherObjectType> + friend class SharedPtr; + + /** + * @brief Drop reference to wrapped object. + * + * If reference counter reaches zero object and its reference + * counter will be deallocated. + **/ + void dropReference(); + + /** + * @brief Wrapped object. + **/ + ObjectType* mObject; + + /** + * @brief Pointer to reference counter. + **/ + uint32_t* mReferenceCounter; + + Deleter deleter_; + void release(); }; -template<typename ObjectType> +template <typename ObjectType> inline utils::SharedPtr<ObjectType>::SharedPtr(ObjectType* Object) - : mObject(NULL), - mReferenceCounter(new uint32_t(1)) { + : mObject(NULL) + , mReferenceCounter(new uint32_t(1)) + , deleter_(DummyDeleter) { DCHECK(Object != NULL); mObject = Object; } -template<typename ObjectType> +template <typename ObjectType> inline utils::SharedPtr<ObjectType>::SharedPtr() - : mObject(0), - mReferenceCounter(0) { -} + : mObject(0), mReferenceCounter(0), deleter_(DummyDeleter) {} -template<typename ObjectType> +template <typename ObjectType> inline utils::SharedPtr<ObjectType>::SharedPtr( - const SharedPtr<ObjectType>& Other) - : mObject(0), - mReferenceCounter(0) { + const SharedPtr<ObjectType>& Other) + : mObject(0), mReferenceCounter(0), deleter_(DummyDeleter) { *this = Other; } -template<typename ObjectType> -template<typename OtherObjectType> +template <typename ObjectType> +template <typename OtherObjectType> inline utils::SharedPtr<ObjectType>::SharedPtr( - const SharedPtr<OtherObjectType>& Other) - : mObject(0), - mReferenceCounter(0) { + const SharedPtr<OtherObjectType>& Other) + : mObject(0), mReferenceCounter(0), deleter_(DummyDeleter) { *this = Other; } -template<typename ObjectType> +template <typename ObjectType> inline utils::SharedPtr<ObjectType>::~SharedPtr() { dropReference(); } -template<typename ObjectType> -inline utils::SharedPtr<ObjectType>& -utils::SharedPtr<ObjectType>::operator=(const SharedPtr<ObjectType>& Other) { +template <typename ObjectType> +inline utils::SharedPtr<ObjectType>& utils::SharedPtr<ObjectType>::operator=( + const SharedPtr<ObjectType>& Other) { return operator=<ObjectType>(Other); } -template<typename ObjectType> -inline bool utils::SharedPtr<ObjectType>::operator ==( - const SharedPtr<ObjectType>& Other) const { +template <typename ObjectType> +inline bool utils::SharedPtr<ObjectType>::operator==( + const SharedPtr<ObjectType>& Other) const { return (mObject == Other.mObject); } -template<typename ObjectType> -inline bool utils::SharedPtr<ObjectType>::operator< ( - const SharedPtr<ObjectType>& other) const { +template <typename ObjectType> +inline bool utils::SharedPtr<ObjectType>::operator<( + const SharedPtr<ObjectType>& other) const { return (mObject < other.mObject); } -template<typename ObjectType> -template<typename OtherObjectType> -inline utils::SharedPtr<ObjectType>& -utils::SharedPtr<ObjectType>::operator=( - const SharedPtr<OtherObjectType>& Other) { +template <typename ObjectType> +template <typename OtherObjectType> +inline utils::SharedPtr<ObjectType>& utils::SharedPtr<ObjectType>::operator=( + const SharedPtr<OtherObjectType>& Other) { dropReference(); mObject = Other.mObject; @@ -271,9 +285,10 @@ utils::SharedPtr<ObjectType>::operator=( return *this; } -template<typename ObjectType> -template<typename OtherObjectType> -utils::SharedPtr<OtherObjectType> utils::SharedPtr<ObjectType>::static_pointer_cast(const SharedPtr<ObjectType>& pointer) { +template <typename ObjectType> +template <typename OtherObjectType> +utils::SharedPtr<OtherObjectType> utils::SharedPtr< + ObjectType>::static_pointer_cast(const SharedPtr<ObjectType>& pointer) { SharedPtr<OtherObjectType> casted_pointer; casted_pointer.mObject = static_cast<OtherObjectType*>(pointer.mObject); casted_pointer.mReferenceCounter = pointer.mReferenceCounter; @@ -285,9 +300,10 @@ utils::SharedPtr<OtherObjectType> utils::SharedPtr<ObjectType>::static_pointer_c return casted_pointer; } -template<typename ObjectType> -template<typename OtherObjectType> -utils::SharedPtr<OtherObjectType> utils::SharedPtr<ObjectType>::dynamic_pointer_cast(const SharedPtr<ObjectType>& pointer) { +template <typename ObjectType> +template <typename OtherObjectType> +utils::SharedPtr<OtherObjectType> utils::SharedPtr< + ObjectType>::dynamic_pointer_cast(const SharedPtr<ObjectType>& pointer) { SharedPtr<OtherObjectType> casted_pointer; casted_pointer.mObject = dynamic_cast<OtherObjectType*>(pointer.mObject); if (NULL != casted_pointer.mObject) { @@ -301,52 +317,51 @@ utils::SharedPtr<OtherObjectType> utils::SharedPtr<ObjectType>::dynamic_pointer_ return casted_pointer; } -template<typename ObjectType> ObjectType* -utils::SharedPtr<ObjectType>::operator->() const { +template <typename ObjectType> +ObjectType* utils::SharedPtr<ObjectType>::operator->() const { DCHECK(mObject); return mObject; } -template<typename ObjectType> ObjectType& -utils::SharedPtr<ObjectType>::operator*() const { +template <typename ObjectType> +ObjectType& utils::SharedPtr<ObjectType>::operator*() const { DCHECK(mObject); return *mObject; } -template<typename ObjectType> +template <typename ObjectType> utils::SharedPtr<ObjectType>::operator bool() const { return valid(); } -template<typename ObjectType> void -utils::SharedPtr<ObjectType>::reset() { +template <typename ObjectType> +void utils::SharedPtr<ObjectType>::reset() { reset_impl(0); } -template<typename ObjectType> void -utils::SharedPtr<ObjectType>::reset(ObjectType* other) { +template <typename ObjectType> +void utils::SharedPtr<ObjectType>::reset(ObjectType* other) { DCHECK(other != NULL); reset_impl(other); } -template<typename ObjectType> +template <typename ObjectType> void SharedPtr<ObjectType>::release() { - - delete mObject; + deleter_(mObject); mObject = 0; delete mReferenceCounter; mReferenceCounter = 0; } -template<typename ObjectType> void -utils::SharedPtr<ObjectType>::reset_impl(ObjectType* other) { +template <typename ObjectType> +void utils::SharedPtr<ObjectType>::reset_impl(ObjectType* other) { dropReference(); mObject = other; mReferenceCounter = new uint32_t(1); } -template<typename ObjectType> +template <typename ObjectType> inline void SharedPtr<ObjectType>::dropReference() { if (0 != mReferenceCounter) { if (1 == atomic_post_dec(mReferenceCounter)) { @@ -355,12 +370,12 @@ inline void SharedPtr<ObjectType>::dropReference() { } } -template<typename ObjectType> +template <typename ObjectType> ObjectType* SharedPtr<ObjectType>::get() const { return mObject; } -template<typename ObjectType> +template <typename ObjectType> inline bool SharedPtr<ObjectType>::valid() const { if (mReferenceCounter && (0 < *mReferenceCounter)) { return (mObject != NULL); diff --git a/src/components/include/utils/threads/async_runner.h b/src/components/include/utils/threads/async_runner.h index c3afe4eea0..c6da0638f4 100644 --- a/src/components/include/utils/threads/async_runner.h +++ b/src/components/include/utils/threads/async_runner.h @@ -52,76 +52,75 @@ namespace threads { * is kind of manager for async functions. */ class AsyncRunner { - public: + public: + /** + * @brief AsyncRunner constructor, allows to create and run new thread. + * The thread will be removed in destructor and appropriate delegate will + * be removed some time latter after pthred_join. + * + * @param thread_name thread's name. + * + * @param delegate delegate to run within thread. + */ + explicit AsyncRunner(const std::string& thread_name); + + /** + * @brief AsyncRun pass obtained delegate into internal queue + * + * @param delegate the objet which has to be concuremtly run + */ + void AsyncRun(threads::ThreadDelegate* delegate); + /** + * @brief Stop delegates activity + */ + void Stop(); + + ~AsyncRunner(); + + private: + class AsyncRunnerDelegate : public threads::ThreadDelegate { + public: + AsyncRunnerDelegate(); + /** - * @brief AsyncRunner constructor, allows to create and run new thread. - * The thread will be removed in destructor and appropriate delegate will - * be removed some time latter after pthred_join. - * - * @param thread_name thread's name. - * - * @param delegate delegate to run within thread. + * @brief threadMain runs delegates queue handling. + */ + virtual void threadMain(); + + /** + * @brief exitThreadMain doing stuff before exit from thread. */ - explicit AsyncRunner(const std::string& thread_name); + virtual void exitThreadMain(); /** - * @brief AsyncRun pass obtained delegate into internal queue + * @brief runDelegate push obtained delegate into specific queue * - * @param delegate the objet which has to be concuremtly run + * @param delegate object that has to be executed. */ - void AsyncRun(threads::ThreadDelegate* delegate); + void runDelegate(threads::ThreadDelegate* delegate); + + private: + /** + * @brief processDelegate allows to pop delegate + * from queue and process it. + */ + void processDelegate(); + /** - * @brief Stop delegates activity + * @brief waitForDelegate wait while delegates queue is empty. */ - void Stop(); - - ~AsyncRunner(); - - private: - - class AsyncRunnerDelegate: public threads::ThreadDelegate { - public: - AsyncRunnerDelegate(); - - /** - * @brief threadMain runs delegates queue handling. - */ - virtual void threadMain(); - - /** - * @brief exitThreadMain doing stuff before exit from thread. - */ - virtual void exitThreadMain(); - - /** - * @brief runDelegate push obtained delegate into specific queue - * - * @param delegate object that has to be executed. - */ - void runDelegate(threads::ThreadDelegate* delegate); - - private: - /** - * @brief processDelegate allows to pop delegate - * from queue and process it. - */ - void processDelegate(); - - /** - * @brief waitForDelegate wait while delegates queue is empty. - */ - void waitForDelegate(); - - std::queue<threads::ThreadDelegate*> delegates_queue_; - sync_primitives::ConditionalVariable delegate_notifier_; - sync_primitives::Lock delegates_queue_lock_; - volatile bool stop_flag_; - }; - - threads::Thread* thread_; - AsyncRunnerDelegate* executor_; + void waitForDelegate(); + + std::queue<threads::ThreadDelegate*> delegates_queue_; + sync_primitives::ConditionalVariable delegate_notifier_; + sync_primitives::Lock delegates_queue_lock_; + volatile bool stop_flag_; + }; + + threads::Thread* thread_; + AsyncRunnerDelegate* executor_; }; -} // namespace threads +} // namespace threads -#endif // SRC_COMPONENTS_INCLUDE_UTILS_ASYNC_RUNNER_H_ +#endif // SRC_COMPONENTS_INCLUDE_UTILS_ASYNC_RUNNER_H_ diff --git a/src/components/include/utils/threads/message_loop_thread.h b/src/components/include/utils/threads/message_loop_thread.h index 6f90df209c..15023f02dd 100644 --- a/src/components/include/utils/threads/message_loop_thread.h +++ b/src/components/include/utils/threads/message_loop_thread.h @@ -41,6 +41,7 @@ #include "utils/message_queue.h" #include "utils/threads/thread.h" #include "utils/shared_ptr.h" +#include "utils/lock.h" namespace threads { @@ -52,7 +53,7 @@ using ::utils::MessageQueue; * to it's queue. To handle messages someone, Handler must be implemented and * passed to MessageLoopThread constructor. */ -template < class Q > +template <class Q> class MessageLoopThread { public: typedef Q Queue; @@ -67,7 +68,8 @@ class MessageLoopThread { * Method called by MessageLoopThread to process single message * from it's queue. After calling this method message is discarded. */ - virtual void Handle(const Message message) = 0; // TODO(dchmerev): Use reference? + // TODO (AKozoriz) : change to const reference (APPLINK-20235) + virtual void Handle(const Message message) = 0; virtual ~Handler() {} }; @@ -86,12 +88,21 @@ class MessageLoopThread { // Process already posted messages and stop thread processing. Thread-safe. void Shutdown(); + // Added for utils/test/auto_trace_test.cc + size_t GetMessageQueueSize() const; + + /* + * Wait until message queue will be empty + */ + void WaitDumpQueue(); + private: /* * Implementation of ThreadDelegate that actually pumps the queue and is * able to correctly shut it down */ - struct LoopThreadDelegate : public threads::ThreadDelegate { + class LoopThreadDelegate : public threads::ThreadDelegate { + public: LoopThreadDelegate(MessageQueue<Message, Queue>* message_queue, Handler* handler); @@ -116,13 +127,17 @@ class MessageLoopThread { ///////// Implementation -template<class Q> -MessageLoopThread<Q>::MessageLoopThread(const std::string& name, - Handler* handler, +template <class Q> +size_t MessageLoopThread<Q>::GetMessageQueueSize() const { + return message_queue_.size(); +} + +template <class Q> +MessageLoopThread<Q>::MessageLoopThread(const std::string& name, + Handler* handler, const ThreadOptions& thread_opts) - : thread_delegate_(new LoopThreadDelegate(&message_queue_, handler)), - thread_(threads::CreateThread(name.c_str(), - thread_delegate_)) { + : 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") @@ -130,10 +145,9 @@ MessageLoopThread<Q>::MessageLoopThread(const std::string& name, } } -template<class Q> +template <class Q> MessageLoopThread<Q>::~MessageLoopThread() { Shutdown(); - thread_->join(); delete thread_delegate_; threads::DeleteThread(thread_); } @@ -145,20 +159,24 @@ void MessageLoopThread<Q>::PostMessage(const Message& message) { template <class Q> void MessageLoopThread<Q>::Shutdown() { - thread_->stop(); + thread_->join(); +} + +template <class Q> +void MessageLoopThread<Q>::WaitDumpQueue() { + message_queue_.WaitUntilEmpty(); } ////////// -template<class Q> +template <class Q> MessageLoopThread<Q>::LoopThreadDelegate::LoopThreadDelegate( MessageQueue<Message, Queue>* message_queue, Handler* handler) - : handler_(*handler), - message_queue_(*message_queue) { + : handler_(*handler), message_queue_(*message_queue) { DCHECK(handler != NULL); DCHECK(message_queue != NULL); } -template<class Q> +template <class Q> void MessageLoopThread<Q>::LoopThreadDelegate::threadMain() { CREATE_LOGGERPTR_LOCAL(logger_, "Utils") LOG4CXX_AUTO_TRACE(logger_); @@ -170,18 +188,20 @@ void MessageLoopThread<Q>::LoopThreadDelegate::threadMain() { DrainQue(); } -template<class Q> +template <class Q> void MessageLoopThread<Q>::LoopThreadDelegate::exitThreadMain() { - CREATE_LOGGERPTR_LOCAL(logger_, "Utils") - LOG4CXX_AUTO_TRACE(logger_); message_queue_.Shutdown(); } -template<class Q> +template <class Q> void MessageLoopThread<Q>::LoopThreadDelegate::DrainQue() { while (!message_queue_.empty()) { - handler_.Handle(message_queue_.pop()); + Message msg; + if (message_queue_.pop(msg)) { + handler_.Handle(msg); + } } } + } // namespace threads #endif // SRC_COMPONENTS_INCLUDE_UTILS_THREADS_MESSAGE_LOOP_THREAD_H_ diff --git a/src/components/include/utils/threads/thread.h b/src/components/include/utils/threads/thread.h index fd2b5e9fd9..c81b912e9a 100644 --- a/src/components/include/utils/threads/thread.h +++ b/src/components/include/utils/threads/thread.h @@ -119,12 +119,11 @@ class Thread { return delegate_lock_; } - ThreadDelegate *delegate() const { + ThreadDelegate* delegate() const { return delegate_; } - void set_delegate(ThreadDelegate *delegate) { - DCHECK(!isThreadRunning_); + void set_delegate(ThreadDelegate* delegate) { delegate_ = delegate; } @@ -132,6 +131,9 @@ class Thread { friend void DeleteThread(Thread* thread); public: + // Yield current thread + static void yield(); + // Get unique ID of currently executing thread static PlatformThreadHandle CurrentId(); @@ -195,6 +197,12 @@ class Thread { } /** + * @brief Checks if invoked in this Thread context + * @return True if called from this Thread class, false otherwise + */ + bool IsCurrentThread() const; + + /** * @brief Thread options. * @return thread options. */ diff --git a/src/components/include/utils/threads/thread_delegate.h b/src/components/include/utils/threads/thread_delegate.h index 66ad30241c..2f2c8b3744 100644 --- a/src/components/include/utils/threads/thread_delegate.h +++ b/src/components/include/utils/threads/thread_delegate.h @@ -39,11 +39,7 @@ namespace threads { -enum ThreadState { - kInit = 0, - kStarted = 1, - kStopReq = 2 -}; +enum ThreadState { kInit = 0, kStarted = 1, kStopReq = 2 }; class Thread; @@ -53,10 +49,7 @@ class Thread; */ class ThreadDelegate { public: - ThreadDelegate() - : state_(kInit), - thread_(NULL) { - } + ThreadDelegate() : state_(kInit), thread_(NULL) {} /** * \brief Thread procedure. */ @@ -76,7 +69,7 @@ class ThreadDelegate { return thread_; } - void set_thread(Thread *thread); + void set_thread(Thread* thread); bool ImproveState(unsigned int to) { state_lock_.Lock(); diff --git a/src/components/include/utils/threads/thread_options.h b/src/components/include/utils/threads/thread_options.h index 797ee0693b..2f5c90ae44 100644 --- a/src/components/include/utils/threads/thread_options.h +++ b/src/components/include/utils/threads/thread_options.h @@ -51,15 +51,12 @@ class ThreadOptions { * @param is_joinable - is thread joinable? */ explicit ThreadOptions(size_t stack_size = 0, bool is_joinable = true) - : stack_size_(stack_size), - is_joinable_(is_joinable) { - } + : stack_size_(stack_size), is_joinable_(is_joinable) {} /** * Dtor. */ - virtual ~ThreadOptions() { - } + virtual ~ThreadOptions() {} /** * Copy ctor. diff --git a/src/components/include/utils/timer_thread.h b/src/components/include/utils/timer_thread.h deleted file mode 100644 index 4236c4e46f..0000000000 --- a/src/components/include/utils/timer_thread.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) 2015, 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_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" -#include "utils/logger.h" -#include "utils/macro.h" -#include "utils/timer_thread.h" -#include "utils/threads/thread.h" -#include "utils/threads/thread_delegate.h" - -namespace timer { -// TODO(AKutsan): Remove this logger after bugfix -CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") - -class TimerDelegate; - -/** - * \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: - * - * Create timer in mobile request - * - * timer::TimerThread<MobileRequest> timer(this, &MobileRequest::onTimeOut); - * timer.start(10); - * - * some actions - * - * To stop timer call timer.stop(); - * - */ -template<class T> -class TimerThread { - 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 timer_thread The Timer_thread pointer - */ - explicit 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 void exitThreadMain(); - - /** - * @brief Set new Timeout - * @param timeout_seconds New timeout to be set - */ - virtual void setTimeOut(const uint32_t timeout_seconds); - - /** - * @brief Quits threadMain function after next loop. - */ - virtual void shouldBeStoped(); - - /** - * @brief Restarts non-loop timer after current iteration. - */ - 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 Default constructor - * - * @param timer_thread The Timer_thread pointer - * @param timeout Timeout to be set - */ - explicit TimerLooperDelegate(TimerThread* timer_thread); - - /** - * @brief Thread main function. - */ - 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), - 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> -TimerThread<T>::~TimerThread() { - LOG4CXX_DEBUG(logger_, "TimerThread is to be destroyed " << name_); - thread_->join(); - delete delegate_; - threads::DeleteThread(thread_); - callback_ = NULL; - callee_ = NULL; -} - -template<class T> -void TimerThread<T>::start(uint32_t timeout_seconds) { - 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> -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_AUTO_TRACE(logger_); - DCHECK(thread_); - LOG4CXX_DEBUG(logger_, "Stopping timer " << name_); - thread_->join(); -} - -template<class T> -bool TimerThread<T>::isRunning() { - DCHECK(thread_); - return thread_->is_running(); -} - -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 { - if (callee_ && callback_) { - (callee_->*callback_)(); - } -} - -template<class T> -TimerThread<T>::TimerDelegate::TimerDelegate(TimerThread* timer_thread) - : 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>::TimerDelegate::~TimerDelegate() { - timer_thread_ = NULL; -} - -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(); - 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) { - 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; - } - } -} - -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(); - ConditionalVariable::WaitStatus wait_status = - 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 << " ms"); - TimerDelegate::timer_thread_->onTimeOut(); - } else { - LOG4CXX_DEBUG(logger_, - "Timeout reset force: " << TimerDelegate::timeout_seconds_); - } - } -} - -template<class T> -void TimerThread<T>::TimerDelegate::exitThreadMain() { - shouldBeStoped(); - termination_condition_.NotifyOne(); -} - -template<class T> -void TimerThread<T>::TimerDelegate::setTimeOut(const uint32_t timeout_seconds) { - timeout_seconds_ = timeout_seconds; - termination_condition_.NotifyOne(); -} - -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 - 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 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_INCLUDE_UTILS_TIMER_THREAD_H_ |