diff options
Diffstat (limited to 'src/components/include')
29 files changed, 718 insertions, 416 deletions
diff --git a/src/components/include/protocol/common.h b/src/components/include/protocol/common.h index f9fdd08fae..6970bc8af4 100644 --- a/src/components/include/protocol/common.h +++ b/src/components/include/protocol/common.h @@ -57,6 +57,7 @@ const uint8_t PROTOCOL_HEADER_V2_SIZE = 12; * First 4-bit field of AppLink protocol packet */ enum { + /** *\brief Constant: number of protocol version (1). */ @@ -71,10 +72,18 @@ enum { *\brief Constant: number of protocol version (3). * Has no difference with v.2 in Mobile_API.xml and frame Header difference * Support SSL with Encryption, Video and Audio services - * Suuport ControlFrame, End Service to/from mobile support, HeartBeat future + * Support ControlFrame, End Service to/from mobile support, HeartBeat feature */ PROTOCOL_VERSION_3 = 0x03, /** + *@brief Constant: number of protocol version (4). + * This protocol is compatibility with version 3 + * Support SSL with Encryption, Video and Audio services + * Support ControlFrame, End Service to/from mobile support, HeartBeat feature, + * SDL4.0 feature. + */ + PROTOCOL_VERSION_4 = 0x04, + /** *\brief Maximum value of packet version field (size 4-bit) specified AppLink Protocol v.7 */ PROTOCOL_VERSION_MAX = 0x0F @@ -216,7 +225,7 @@ enum RESULT_CODE { RESULT_REASSIGN = 12, RESULT_XML_PARSING = 13, RESULT_RESEND_ACK = 14, - RESULT_DEFRERRED = 15, + RESULT_DEFERRED = 15, RESULT_ENCRYPTION_FAILED = 16, RESULT_HEARTBEAT_IS_NOT_SUPPORTED = 17, RESULT_UNKNOWN = 255 diff --git a/src/components/include/protocol/raw_message.h b/src/components/include/protocol/raw_message.h index 09b5eafb7e..f9a035e174 100644 --- a/src/components/include/protocol/raw_message.h +++ b/src/components/include/protocol/raw_message.h @@ -78,7 +78,7 @@ class RawMessage { /** * \brief Getter for message size */ - size_t data_size() const; + size_t data_size() const; /** * \brief Getter for actual data size */ diff --git a/src/components/include/protocol/service_type.h b/src/components/include/protocol/service_type.h index ab049be9b7..b5870e0af1 100644 --- a/src/components/include/protocol/service_type.h +++ b/src/components/include/protocol/service_type.h @@ -61,7 +61,6 @@ const uint8_t SERVICE_TYPE_NAVI = 0x0B; */ const uint8_t SERVICE_TYPE_BULK = 0x0F; - /** * \brief Enum describing possible types of sessions: RPC for API messages, Navi for video streaming, bulk for PutFile. @@ -83,5 +82,4 @@ ServiceType ServiceTypeFromByte(uint8_t type); uint8_t ServiceTypeToByte(ServiceType type); } // namespace protocol_handler - #endif // SRC_COMPONENTS_INCLUDE_PROTOCOL_SERVICE_TYPE_H_ diff --git a/src/components/include/protocol_handler/protocol_handler.h b/src/components/include/protocol_handler/protocol_handler.h index e0d4fde8cd..9bb77ae483 100644 --- a/src/components/include/protocol_handler/protocol_handler.h +++ b/src/components/include/protocol_handler/protocol_handler.h @@ -97,6 +97,10 @@ class ProtocolHandler { */ virtual void SendEndSession(int32_t connection_id, uint8_t session_id) = 0; + virtual void SendEndService(int32_t connection_id, + uint8_t session_id, + uint8_t service_type) = 0; + protected: /** * \brief Destructor diff --git a/src/components/include/protocol_handler/session_observer.h b/src/components/include/protocol_handler/session_observer.h index 9a958f6fa7..355c62e646 100644 --- a/src/components/include/protocol_handler/session_observer.h +++ b/src/components/include/protocol_handler/session_observer.h @@ -96,6 +96,20 @@ class SessionObserver { const protocol_handler::ServiceType &service_type) = 0; /** + * \brief Callback function used by ProtocolHandler + * when Mobile Application start message flood + * \param connection_key used by other components as application identifier + */ + virtual void OnApplicationFloodCallBack(const uint32_t &connection_key) = 0; + + /** + * \brief Callback function used by ProtocolHandler + * when Mobile Application sends malformed message + * \param connection_key used by other components as application identifier + */ + virtual void OnMalformedMessageCallback(const uint32_t &connection_key) = 0; + + /** * \brief Creates unique identifier of session (can be used as hash) * from given connection identifier * within which session exists and session number. @@ -157,6 +171,17 @@ class SessionObserver { transport_manager::ConnectionUID connection_handle, uint8_t session_id) = 0; + /** + * @brief returns protocol version which application supports + * @param connection_id id of connection + * @param session_id id of session + * @param method writes value protocol version to protocol_version + * @return TRUE if session and connection exist otherwise returns FALSE + */ + virtual bool ProtocolVersionUsed(uint32_t connection_id, + uint8_t session_id, uint8_t& protocol_version) = 0; + + #ifdef ENABLE_SECURITY /** * \brief Sets crypto context of connection diff --git a/src/components/include/security_manager/crypto_manager.h b/src/components/include/security_manager/crypto_manager.h index 87cfc1397f..00c3833e62 100644 --- a/src/components/include/security_manager/crypto_manager.h +++ b/src/components/include/security_manager/crypto_manager.h @@ -50,7 +50,7 @@ namespace security_manager { class SSLContext; enum Mode { CLIENT, SERVER }; -enum Protocol { SSLv3, TLSv1, TLSv1_1, TLSv1_2 }; +enum Protocol { SSLv3, TLSv1, TLSv1_1, TLSv1_2}; class CryptoManager { public: diff --git a/src/components/include/transport_manager/transport_adapter/device.h b/src/components/include/transport_manager/transport_adapter/device.h index 78d3b44958..e7bca5a46b 100644 --- a/src/components/include/transport_manager/transport_adapter/device.h +++ b/src/components/include/transport_manager/transport_adapter/device.h @@ -76,6 +76,8 @@ class Device { virtual ApplicationList GetApplicationList() const = 0; + virtual void Stop() { } + inline const DeviceUID& unique_device_id() const { return unique_device_id_; } diff --git a/src/components/include/transport_manager/transport_adapter/transport_adapter.h b/src/components/include/transport_manager/transport_adapter/transport_adapter.h index 2edf173110..b73333e535 100644 --- a/src/components/include/transport_manager/transport_adapter/transport_adapter.h +++ b/src/components/include/transport_manager/transport_adapter/transport_adapter.h @@ -1,4 +1,4 @@ -/** +/* * \file transport_adapter.h * \brief TransportAdapter class header file. * @@ -123,6 +123,12 @@ class TransportAdapter { virtual Error Init() = 0; /** + * @brief Stops device adapter + * Called from transport manager to stop device adapter + */ + virtual void Terminate() = 0; + + /** * @brief Add listener to the container(list) of device adapter listeners. * * @param listener Pointer to the device adapter listener. diff --git a/src/components/include/transport_manager/transport_manager.h b/src/components/include/transport_manager/transport_manager.h index 40790ac0ab..25745e7485 100644 --- a/src/components/include/transport_manager/transport_manager.h +++ b/src/components/include/transport_manager/transport_manager.h @@ -59,6 +59,12 @@ class TransportManager { virtual int Init() = 0; /** + * @brief Reinitializes transport manager + * @return Error code + */ + virtual int Reinit() = 0; + + /** * @brief Start scanning for new devices. * * @return Code error. diff --git a/src/components/include/transport_manager/transport_manager_listener.h b/src/components/include/transport_manager/transport_manager_listener.h index 5033a95d17..0684e8f22f 100644 --- a/src/components/include/transport_manager/transport_manager_listener.h +++ b/src/components/include/transport_manager/transport_manager_listener.h @@ -143,7 +143,7 @@ class TransportManagerListener { /** * @brief Notifies about recieving message from TM. * - * @param message Recieved message + * @param message Received message **/ virtual void OnTMMessageReceived(const ::protocol_handler::RawMessagePtr message) = 0; diff --git a/src/components/include/utils/atomic.h b/src/components/include/utils/atomic.h index bfbcff9dc9..f80455b748 100644 --- a/src/components/include/utils/atomic.h +++ b/src/components/include/utils/atomic.h @@ -28,15 +28,15 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. -*/ + */ + +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_ #ifdef __QNXNTO__ #include <atomic.h> #endif -#ifndef SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_ -#define SRC_COMPONENTS_INCLUDE_UTILS_ATOMIC_H_ - #if defined(__QNXNTO__) #define atomic_post_inc(ptr) atomic_add_value((ptr), 1) #elif defined(__GNUG__) diff --git a/src/components/include/utils/conditional_variable.h b/src/components/include/utils/conditional_variable.h index 58119a0cfd..1f0a7e62de 100644 --- a/src/components/include/utils/conditional_variable.h +++ b/src/components/include/utils/conditional_variable.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -43,6 +43,7 @@ namespace sync_primitives { class AutoLock; +class Lock; namespace impl { #if defined(OS_POSIX) @@ -80,7 +81,8 @@ class ConditionalVariable { void Broadcast(); // Wait forever or up to milliseconds time limit - void Wait(AutoLock& auto_lock); + bool Wait(AutoLock& auto_lock); + bool Wait(Lock& lock); WaitStatus WaitFor(AutoLock& auto_lock, int32_t milliseconds); private: impl::PlatformConditionalVariable cond_var_; diff --git a/src/components/include/utils/data_accessor.h b/src/components/include/utils/data_accessor.h index f5e99797ba..344d6e34a8 100644 --- a/src/components/include/utils/data_accessor.h +++ b/src/components/include/utils/data_accessor.h @@ -33,40 +33,42 @@ #define SRC_COMPONENTS_INCLUDE_UTILS_DATA_ACCESSOR_H_ #include "utils/lock.h" +#include "utils/shared_ptr.h" // This class is for thread-safe access to data template<class T> class DataAccessor { public: DataAccessor(const T& data, const sync_primitives::Lock& lock) - : data_(data) - , lock_(const_cast<sync_primitives::Lock&>(lock)) - , counter_(0) { - lock_.Acquire(); + : data_(data), + lock_(const_cast<sync_primitives::Lock&>(lock)), + counter_( new uint32_t(0)) { + lock_.Acquire(); } - template<class O> DataAccessor(const DataAccessor<O>& other) - : data_(other.data_) - , lock_(other.lock_) - , counter_(other.counter_) { - ++counter_; + + DataAccessor(const DataAccessor<T>& other) + : data_(other.data_), + lock_(other.lock_), + counter_(other.counter_) { + ++(*counter_); } + ~DataAccessor() { - if (counter_ > 0) { - --counter_; - } - if (0 == counter_) { - lock_.Release(); + if (0 == *counter_) { + lock_.Release(); + } else { + --(*counter_); } } const T& GetData() const { return data_; } private: - template <class O> const DataAccessor<T>& operator=(const DataAccessor<O>& other); - const T& data_; - sync_primitives::Lock& lock_; - uint32_t counter_; + void *operator new(size_t size); + const T& data_; + sync_primitives::Lock& lock_; + utils::SharedPtr<uint32_t> counter_; }; #endif // SRC_COMPONENTS_INCLUDE_UTILS_DATA_ACCESSOR_H_ diff --git a/src/components/include/utils/date_time.h b/src/components/include/utils/date_time.h index 766932652d..c8cef32ef4 100644 --- a/src/components/include/utils/date_time.h +++ b/src/components/include/utils/date_time.h @@ -1,34 +1,34 @@ /* -* Copyright (c) 2014, Ford Motor Company -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following -* disclaimer in the documentation and/or other materials provided with the -* distribution. -* -* Neither the name of the Ford Motor Company nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ #ifndef SRC_COMPONENTS_INCLUDE_UTILS_DATE_TIME_H_ #define SRC_COMPONENTS_INCLUDE_UTILS_DATE_TIME_H_ @@ -50,6 +50,7 @@ class DateTime { public: static const int32_t MILLISECONDS_IN_SECOND = 1000; static const int32_t MICROSECONDS_IN_MILLISECONDS = 1000; + static const int32_t MICROSECONDS_IN_SECOND = 1000 * 1000; static TimevalStruct getCurrentTime(); @@ -80,5 +81,6 @@ class DateTime { }; } // namespace date_time - +bool operator<(const TimevalStruct& time1, const TimevalStruct& time2); +bool operator==(const TimevalStruct& time1, const TimevalStruct& time2); #endif // SRC_COMPONENTS_INCLUDE_UTILS_DATE_TIME_H_ diff --git a/src/components/include/utils/lock.h b/src/components/include/utils/lock.h index 910a88052f..29bd467143 100644 --- a/src/components/include/utils/lock.h +++ b/src/components/include/utils/lock.h @@ -34,11 +34,14 @@ #if defined(OS_POSIX) #include <pthread.h> +#include <sched.h> #else #error Please implement lock for your OS #endif #include <stdint.h> #include "utils/macro.h" +#include "utils/atomic.h" +#include "utils/memory_barrier.h" namespace sync_primitives { @@ -48,6 +51,31 @@ typedef pthread_mutex_t PlatformMutex; #endif } // namespace impl + +class SpinMutex { + public: + SpinMutex() + : state_(0) { } + void Lock() { + if (atomic_post_set(&state_) == 0) { + return; + } + for(;;) { + sched_yield(); + if (state_ == 0 && atomic_post_set(&state_) == 0) { + return; + } + } + } + void Unlock() { + state_ = 0; + } + ~SpinMutex() { + } + private: + volatile unsigned int state_; +}; + /* Platform-indepenednt NON-RECURSIVE lock (mutex) wrapper Please use AutoLock to ackquire and (automatically) release it It eases balancing of multple lock taking/releasing and makes it diff --git a/src/components/include/utils/logger.h b/src/components/include/utils/logger.h index 7c00c5d3aa..50d194245c 100644 --- a/src/components/include/utils/logger.h +++ b/src/components/include/utils/logger.h @@ -30,6 +30,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ + + #ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_ #define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_ @@ -37,11 +39,11 @@ #include <errno.h> #include <string.h> #include <sstream> - #include <apr_time.h> #include <log4cxx/propertyconfigurator.h> #include <log4cxx/spi/loggingevent.h> #include "utils/push_log.h" #include "utils/logger_status.h" + #include "utils/auto_trace.h" #endif // ENABLE_LOG #ifdef ENABLE_LOG @@ -57,19 +59,23 @@ #define INIT_LOGGER(file_name) \ log4cxx::PropertyConfigurator::configure(file_name); - // without this line log4cxx threads continue using some instances destroyed by exit() - #define DEINIT_LOGGER() \ - log4cxx::Logger::getRootLogger()->closeNestedAppenders(); + // Logger deinitilization function and macro, need to stop log4cxx writing + // without this deinitilization log4cxx threads continue using some instances destroyed by exit() + void deinit_logger (); + #define DEINIT_LOGGER() deinit_logger() #define LOG4CXX_IS_TRACE_ENABLED(logger) logger->isTraceEnabled() + log4cxx_time_t time_now(); + #define LOG_WITH_LEVEL(loggerPtr, logLevel, logEvent) \ do { \ if (logger::logger_status != logger::DeletingLoggerThread) { \ if (loggerPtr->isEnabledFor(logLevel)) { \ std::stringstream accumulator; \ accumulator << logEvent; \ - logger::push_log(loggerPtr, logLevel, accumulator.str(), apr_time_now(), LOG4CXX_LOCATION, ::log4cxx::spi::LoggingEvent::getCurrentThreadName()); \ + logger::push_log(loggerPtr, logLevel, accumulator.str(), time_now(), \ + LOG4CXX_LOCATION, ::log4cxx::spi::LoggingEvent::getCurrentThreadName()); \ } \ } \ } while (false) @@ -110,8 +116,8 @@ #undef LOG4CXX_TRACE #define LOG4CXX_TRACE(loggerPtr, logEvent) LOG_WITH_LEVEL(loggerPtr, ::log4cxx::Level::getTrace(), logEvent) - #define LOG4CXX_TRACE_ENTER(logger) LOG4CXX_TRACE(logger, "ENTER: " << __PRETTY_FUNCTION__ ) - #define LOG4CXX_TRACE_EXIT(logger) LOG4CXX_TRACE(logger, "EXIT: " << __PRETTY_FUNCTION__ ) + #define LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, auto_trace) logger::AutoTrace auto_trace(loggerPtr, LOG4CXX_LOCATION) + #define LOG4CXX_AUTO_TRACE(loggerPtr) LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, SDL_local_auto_trace_object) #define LOG4CXX_ERROR_WITH_ERRNO(logger, message) \ LOG4CXX_ERROR(logger, message << ", error code " << errno << " (" << strerror(errno) << ")") @@ -173,8 +179,8 @@ #define LOG4CXX_FATAL_EXT(logger, logEvent) #define LOG4CXX_FATAL_STR_EXT(logger, logEvent) - #define LOG4CXX_TRACE_ENTER(logger) - #define LOG4CXX_TRACE_EXIT(logger) + #define LOG4CXX_AUTO_TRACE_WITH_NAME_SPECIFIED(loggerPtr, auto_trace) + #define LOG4CXX_AUTO_TRACE(loggerPtr) #endif // ENABLE_LOG #endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOGGER_H_ diff --git a/src/components/include/utils/logger_status.h b/src/components/include/utils/logger_status.h index e28fa6f839..17fa0562c2 100644 --- a/src/components/include/utils/logger_status.h +++ b/src/components/include/utils/logger_status.h @@ -45,7 +45,7 @@ typedef enum { // this variable is only changed when creating and deleting logger thread // its reads and writes are believed to be atomic // thus it shall be considered thread safe -extern LoggerStatus logger_status; +extern volatile LoggerStatus logger_status; } // namespace logger diff --git a/src/components/include/utils/macro.h b/src/components/include/utils/macro.h index bf34b199b5..bfd13411f4 100644 --- a/src/components/include/utils/macro.h +++ b/src/components/include/utils/macro.h @@ -32,8 +32,12 @@ #ifndef SRC_COMPONENTS_INCLUDE_UTILS_MACRO_H_ #define SRC_COMPONENTS_INCLUDE_UTILS_MACRO_H_ +#ifdef DEBUG #include <assert.h> +#else // RELEASE #include <stdio.h> +#endif +#include "logger.h" @@ -54,14 +58,53 @@ #define FRIEND_DELETER_DESTRUCTOR(TypeName) \ friend utils::deleters::Deleter<TypeName>::~Deleter() +#ifdef DEBUG + #define ASSERT(condition) \ + do { \ + DEINIT_LOGGER(); \ + assert(condition); \ + } while (false) +#else // RELEASE + #define ASSERT(condition) \ + fprintf(stderr, "Failed condition \"" #condition "\" [%s:%d][%s]\n\n", \ + __FILE__, __LINE__, __FUNCTION__) +#endif + #define DCHECK(condition) \ if (!(condition)) { \ - printf("\nDCHECK [%s:%d][%s]", __FILE__, __LINE__, __FUNCTION__); \ - printf("[Check failed: " #condition "]\n\n"); \ - assert(false); \ + CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \ + LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \ + << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']'); \ + ASSERT((condition)); \ + } + +/* + * Will cauch assert on debug version, + * Will return return_value in release build + */ +#define DCHECK_OR_RETURN(condition, return_value) \ + if (!(condition)) { \ + CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \ + LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \ + << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']' ); \ + ASSERT((condition)); \ + return (return_value); \ + } +/* + * Will cauch assert on debug version, + * Will return return_value in release build + */ +#define DCHECK_OR_RETURN_VOID(condition) \ + if (!(condition)) { \ + CREATE_LOGGERPTR_LOCAL(logger_, "assert"); \ + LOG4CXX_FATAL(logger_, "DCHECK failed with \"" << #condition \ + << "\" [" << __FUNCTION__ << "][" << __FILE__ << ':' << __LINE__ << ']' ); \ + ASSERT((condition)); \ + return ; \ } -#define NOTREACHED() DCHECK(false) + +#define NOTREACHED() DCHECK(!"Unreachable code") // Allows to perform static check that virtual function from base class is // actually being overriden if compiler support is available @@ -79,4 +122,9 @@ */ #define ARRAYSIZE(arr) sizeof (arr) / sizeof(*arr) +#ifdef BUILD_TESTS +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test +#endif + #endif // SRC_COMPONENTS_INCLUDE_UTILS_MACRO_H_ diff --git a/src/components/include/utils/memory_barrier.h b/src/components/include/utils/memory_barrier.h index 312894e034..43c7c9df14 100644 --- a/src/components/include/utils/memory_barrier.h +++ b/src/components/include/utils/memory_barrier.h @@ -28,7 +28,7 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. -*/ + */ #ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_MEMORY_BARRIER_H_ #define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_MEMORY_BARRIER_H_ diff --git a/src/components/include/utils/message_queue.h b/src/components/include/utils/message_queue.h index 9d998cc698..a187328e13 100644 --- a/src/components/include/utils/message_queue.h +++ b/src/components/include/utils/message_queue.h @@ -28,10 +28,10 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. -*/ + */ -#ifndef MESSAGE_QUEUE_CLASS -#define MESSAGE_QUEUE_CLASS +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_ #include <queue> @@ -44,7 +44,9 @@ * \class MessageQueue * \brief Wrapper for multithreading queue. */ - //TODO(Ezamakhov): move to utils namespace + +namespace utils { + template<typename T, class Q = std::queue<T> > class MessageQueue { public: typedef Q Queue; @@ -107,7 +109,6 @@ template<typename T, class Q = std::queue<T> > class MessageQueue { void Reset(); private: - /** *\brief Queue */ @@ -193,4 +194,6 @@ template<typename T, class Q> void MessageQueue<T, Q>::Reset() { } } -#endif // MESSAGE_QUEUE_CLASS +} // namespace utils + +#endif // SRC_COMPONENTS_INCLUDE_UTILS_MESSAGE_QUEUE_H_ diff --git a/src/components/include/utils/prioritized_queue.h b/src/components/include/utils/prioritized_queue.h index 4bec901f59..2a8ebf0a7b 100644 --- a/src/components/include/utils/prioritized_queue.h +++ b/src/components/include/utils/prioritized_queue.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/include/utils/rwlock.h b/src/components/include/utils/rwlock.h index b5042acbfe..1083dbd63f 100644 --- a/src/components/include/utils/rwlock.h +++ b/src/components/include/utils/rwlock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,8 +30,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RWLOCK_H_ -#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RWLOCK_H_ +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_RWLOCK_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_RWLOCK_H_ #if defined(OS_POSIX) #include <pthread.h> @@ -49,21 +49,91 @@ typedef pthread_rwlock_t PlatformRWLock; #endif } // namespace impl +/** + * RW locks wrapper + * Read-write locks permit concurrent reads and exclusive writes to a protected shared resource. + * The read-write lock is a single entity that can be locked in read or write mode. + * To modify a resource, a thread must first acquire the exclusive write lock. + * An exclusive write lock is not permitted until all read locks have been released. + */ + class RWLock { public: RWLock(); ~RWLock(); - void AcquireForReading(); - void AcquireForWriting(); - void Release(); + + /** + * @brief Acqure read-write lock for reading. + * The calling thread acquires the read lock if a writer does not + * hold the lock and there are no writers blocked on the lock. + * It is unspecified whether the calling thread acquires the lock + * when a writer does not hold the lock and there are writers waiting for the lock. + * If a writer holds the lock, the calling thread will not acquire the read lock. + * If the read lock is not acquired, the calling thread blocks + * (that is, it does not return from the AcquireForReading()) until it can acquire the lock. + * Results are undefined if the calling thread holds a write lock on rwlock at the time the call is made. + * A thread can hold multiple concurrent read locks on rwlock + * (that is, successfully call AcquireForReading() n times) + * If so, the thread must perform matching unlocks (that is, it must call Release() n times). + * @returns true if lock was acquired and false if was not + */ + bool AcquireForReading(); + + /** + * @brief try to Acqure read-write lock for reading. + * Applies a read lock as in AcquireForReading() + * with the exception that the function fails if any thread + * holds a write lock on rwlock or there are writers blocked on rwlock. + * But not blocks calling thread. + * @returns true if lock was acquired and false if was not + */ + bool TryAcquireForReading(); + + /** + * @brief Try to Acqure read-write lock for writing. + * Applies a write lock like AcquireForWriting(), with the exception that the + * function fails if any thread currently holds rwlock (for reading or writing) + * Invoke of TryAcquireForWriting will not block calling thread and returns "false" + * @returns true if lock was acquired and false if was not + */ + bool TryAcquireForWriting(); + + /** + * @brief Acqure read-write lock for writing. + * Applies a write lock to the read-write lock. + * The calling thread acquires the write lock if no other thread (reader or writer) + * holds the read-write lock rwlock. Otherwise, the thread blocks + * (that is, does not return from the AcquireForWriting() call) + * until it can acquire the lock. + * Results are undefined if the calling thread holds the read-write lock (whether a read or write lock) + * at the time the call is made. + * The thread must perform matching unlock (that is, it must call Release()). + * @returns true if lock was acquired and false if was not + */ + bool AcquireForWriting(); + + /** + * @brief Release read-write lock. + * Releases a lock held on the read-write lock object. + * Results are undefined if the read-write lock rwlock + * is not held by the calling thread. + * @returns true if lock was released and false if was not + */ + bool Release(); private: impl::PlatformRWLock rwlock_; }; +/** + * @brief Makes auto lock read-write locks for reading + * Please use AutoReadLock to acquire for reading and (automatically) release it + */ + class AutoReadLock { public: - explicit AutoReadLock(RWLock& rwlock) : rwlock_(rwlock) { + explicit AutoReadLock(RWLock& rwlock) + : rwlock_(rwlock) { rwlock_.AcquireForReading(); } ~AutoReadLock() { @@ -72,13 +142,17 @@ class AutoReadLock { private: RWLock& rwlock_; - DISALLOW_COPY_AND_ASSIGN(AutoReadLock); }; +/** + * @brief Makes auto lock read-write locks for writing + * Please use AutoWriteLock to acquire for writing and (automatically) release it + */ class AutoWriteLock { public: - explicit AutoWriteLock(RWLock& rwlock) : rwlock_(rwlock) { + explicit AutoWriteLock(RWLock& rwlock) + : rwlock_(rwlock) { rwlock_.AcquireForWriting(); } ~AutoWriteLock() { @@ -87,10 +161,9 @@ class AutoWriteLock { private: RWLock& rwlock_; - DISALLOW_COPY_AND_ASSIGN(AutoWriteLock); }; } // namespace sync_primitives -#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RWLOCK_H_ +#endif // SRC_COMPONENTS_INCLUDE_UTILS_RWLOCK_H_ diff --git a/src/components/include/utils/shared_ptr.h b/src/components/include/utils/shared_ptr.h index 604bee998b..f506c6018e 100644 --- a/src/components/include/utils/shared_ptr.h +++ b/src/components/include/utils/shared_ptr.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -164,7 +164,6 @@ class SharedPtr { operator bool() const; void reset(); void reset(ObjectType* other); - void release(); ObjectType* get() const; /** @@ -197,6 +196,8 @@ class SharedPtr { * @brief Pointer to reference counter. **/ uint32_t* mReferenceCounter; + + void release(); }; template<typename ObjectType> diff --git a/src/components/include/utils/threads/CMakeLists.txt b/src/components/include/utils/threads/CMakeLists.txt new file mode 100644 index 0000000000..f97039c21b --- /dev/null +++ b/src/components/include/utils/threads/CMakeLists.txt @@ -0,0 +1,5 @@ +set(UtilsIncludeDir ${COMPONENTS_DIR/utils/include) + +include_directories ( + ${UtilsIncludeDir} +)
\ No newline at end of file diff --git a/src/components/include/utils/threads/message_loop_thread.h b/src/components/include/utils/threads/message_loop_thread.h index e051c48904..6f90df209c 100644 --- a/src/components/include/utils/threads/message_loop_thread.h +++ b/src/components/include/utils/threads/message_loop_thread.h @@ -39,13 +39,16 @@ #include "utils/logger.h" #include "utils/macro.h" #include "utils/message_queue.h" -#include "utils/threads/thread_manager.h" -#include "utils/lock.h" +#include "utils/threads/thread.h" +#include "utils/shared_ptr.h" namespace threads { -/* - * Class that handles a thread which sole purpose is to pump messages pushed +using ::utils::MessageQueue; + +/** + * \class MessageLoopThread + * \brief Handles a thread which sole purpose is to pump messages pushed * to it's queue. To handle messages someone, Handler must be implemented and * passed to MessageLoopThread constructor. */ @@ -79,6 +82,10 @@ class MessageLoopThread { // Places a message to the therad's queue. Thread-safe. void PostMessage(const Message& message); + + // Process already posted messages and stop thread processing. Thread-safe. + void Shutdown(); + private: /* * Implementation of ThreadDelegate that actually pumps the queue and is @@ -90,19 +97,20 @@ class MessageLoopThread { // threads::ThreadDelegate overrides virtual void threadMain() OVERRIDE; - virtual bool exitThreadMain() OVERRIDE; + virtual void exitThreadMain() OVERRIDE; + private: // Handle all messages that are in the queue until it is empty void DrainQue(); - private: // Handler that processes messages Handler& handler_; // Message queue that is actually owned by MessageLoopThread MessageQueue<Message, Queue>& message_queue_; - sync_primitives::Lock active_lock; }; + private: MessageQueue<Message, Queue> message_queue_; + LoopThreadDelegate* thread_delegate_; threads::Thread* thread_; }; @@ -112,8 +120,10 @@ template<class Q> MessageLoopThread<Q>::MessageLoopThread(const std::string& name, Handler* handler, const ThreadOptions& thread_opts) - : thread_(threads::CreateThread(name.c_str(), new LoopThreadDelegate(&message_queue_, handler))) { - bool started = thread_->startWithOptions(thread_opts); + : thread_delegate_(new LoopThreadDelegate(&message_queue_, handler)), + thread_(threads::CreateThread(name.c_str(), + thread_delegate_)) { + const bool started = thread_->start(thread_opts); if (!started) { CREATE_LOGGERPTR_LOCAL(logger_, "Utils") LOG4CXX_ERROR(logger_, "Failed to start thread " << name); @@ -122,7 +132,10 @@ MessageLoopThread<Q>::MessageLoopThread(const std::string& name, template<class Q> MessageLoopThread<Q>::~MessageLoopThread() { - thread_->stop(); + Shutdown(); + thread_->join(); + delete thread_delegate_; + threads::DeleteThread(thread_); } template <class Q> @@ -130,6 +143,11 @@ void MessageLoopThread<Q>::PostMessage(const Message& message) { message_queue_.push(message); } +template <class Q> +void MessageLoopThread<Q>::Shutdown() { + thread_->stop(); +} + ////////// template<class Q> MessageLoopThread<Q>::LoopThreadDelegate::LoopThreadDelegate( @@ -142,8 +160,9 @@ MessageLoopThread<Q>::LoopThreadDelegate::LoopThreadDelegate( template<class Q> void MessageLoopThread<Q>::LoopThreadDelegate::threadMain() { - sync_primitives::AutoLock auto_lock(active_lock); - while(!message_queue_.IsShuttingDown()){ + CREATE_LOGGERPTR_LOCAL(logger_, "Utils") + LOG4CXX_AUTO_TRACE(logger_); + while (!message_queue_.IsShuttingDown()) { DrainQue(); message_queue_.wait(); } @@ -152,18 +171,15 @@ void MessageLoopThread<Q>::LoopThreadDelegate::threadMain() { } template<class Q> -bool MessageLoopThread<Q>::LoopThreadDelegate::exitThreadMain() { +void MessageLoopThread<Q>::LoopThreadDelegate::exitThreadMain() { + CREATE_LOGGERPTR_LOCAL(logger_, "Utils") + LOG4CXX_AUTO_TRACE(logger_); message_queue_.Shutdown(); - { - sync_primitives::AutoLock auto_lock(active_lock); - // Prevent canceling thread until queue is drained - } - return true; } template<class Q> void MessageLoopThread<Q>::LoopThreadDelegate::DrainQue() { - while(!message_queue_.empty()) { + while (!message_queue_.empty()) { handler_.Handle(message_queue_.pop()); } } diff --git a/src/components/include/utils/threads/thread.h b/src/components/include/utils/threads/thread.h index 3b81cf3454..fd2b5e9fd9 100644 --- a/src/components/include/utils/threads/thread.h +++ b/src/components/include/utils/threads/thread.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,19 +43,19 @@ #include "utils/macro.h" #include "utils/threads/thread_delegate.h" #include "utils/threads/thread_options.h" +#include "utils/conditional_variable.h" +#include "utils/lock.h" namespace threads { -namespace impl { #if defined(OS_POSIX) typedef pthread_t PlatformThreadHandle; #else #error Please implement thread for your OS #endif -} /** - * Non platform specific thread abstraction that establishes a + * @brief Non platform specific thread abstraction that establishes a * threads::ThreadDelegate on a new thread. * * ThreadDelegate example: @@ -75,60 +75,72 @@ typedef pthread_t PlatformThreadHandle; * thread.join(); * printf("ok!\n"); */ + class Thread; +void enqueue_to_join(Thread* thread); + Thread* CreateThread(const char* name, ThreadDelegate* delegate); -void DeleteThread(Thread*); +void DeleteThread(Thread* thread); class Thread { - friend Thread* CreateThread(const char*, ThreadDelegate*); - friend void DeleteThread(Thread*); - public: - /** - * Class that represents unique in-process thread identifier - * due to restriction of pthread API it only allows checks - * for equality to different thread id and no ordering. - * - * ostream<< operator is provided for this class which - * outputs thread name associated to an identifier. - */ - class Id { - public: - explicit Id(const impl::PlatformThreadHandle& id): id_(id) {} - bool operator==(const Id& that) const; - impl::PlatformThreadHandle Handle() const { return id_; } - private: - impl::PlatformThreadHandle id_; - friend class Thread; - }; - - // Get unique ID of currently executing thread - static Id CurrentId(); - - // Get name associated with thread identified by thread_id - static std::string NameFromId(const Id& thread_id); - - // Give thread thread_id a name, helpful for debugging - static void SetNameForId(const Id& thread_id, const std::string& name); + private: + const std::string name_; + // Should be locked to protect delegate_ value + sync_primitives::Lock delegate_lock_; + ThreadDelegate* delegate_; + PlatformThreadHandle handle_; + ThreadOptions thread_options_; + // Should be locked to protect isThreadRunning_ and thread_created_ values + sync_primitives::Lock state_lock_; + volatile unsigned int isThreadRunning_; + volatile bool stopped_; + volatile bool finalized_; + bool thread_created_; + // Signalled when Thread::start() is called + sync_primitives::ConditionalVariable run_cond_; + public: /** - * Starts the thread. + * @brief Starts the thread. * @return true if the thread was successfully started. */ bool start(); - ThreadDelegate* delegate() const; - /** - * Starts the thread. Behaves exactly like Start in addition to + * @brief Starts the thread. Behaves exactly like \ref start() in addition to * allow to override the default options. - * @param options - thread options. Look for 'threads/thread_options.h' + * @param options Thread options. Look for 'threads/thread_options.h' * for details. * @return true if the thread was successfully started. */ - bool startWithOptions(const ThreadOptions& options); + bool start(const ThreadOptions& options); + + sync_primitives::Lock& delegate_lock() { + return delegate_lock_; + } + + ThreadDelegate *delegate() const { + return delegate_; + } + + void set_delegate(ThreadDelegate *delegate) { + DCHECK(!isThreadRunning_); + delegate_ = delegate; + } + + friend Thread* CreateThread(const char* name, ThreadDelegate* delegate); + friend void DeleteThread(Thread* thread); + + public: + // Get unique ID of currently executing thread + static PlatformThreadHandle CurrentId(); + + // Give thread thread_id a name, helpful for debugging + static void SetNameForId(const PlatformThreadHandle& thread_id, + std::string name); /** - * Signals the thread to exit and returns once the thread has exited. + * @brief Signals the thread to exit and returns once the thread has exited. * After this method returns, the Thread object is completely reset and may * be used as if it were newly constructed (i.e., Start may be called again). * @@ -137,16 +149,18 @@ class Thread { */ void stop(); + void join(); + /** - * Get thread name. + * @brief Get thread name. * @return thread name */ - const std::string& thread_name() { + const std::string& name() { return name_; } /** - * Returns true if the thread has been started, and not yet stopped. + * @brief Returns true if the thread has been started, and not yet stopped. * When a thread is running, the thread_id_ is non-zero. * @return true if the thread has been started, and not yet stopped. */ @@ -154,12 +168,10 @@ class Thread { return isThreadRunning_; } - void set_running(bool running) { - isThreadRunning_ = running; - } + void set_running(bool running); /** - * Is thread joinable? + * @brief Is thread joinable? * @return - Returns true if the thread is joinable. */ bool is_joinable() const { @@ -167,7 +179,7 @@ class Thread { } /** - * Thread stack size + * @brief Thread stack size * @return thread stack size */ size_t stack_size() const { @@ -175,23 +187,15 @@ class Thread { } /** - * The native thread handle. + * @brief The native thread handle. * @return thread handle. */ - impl::PlatformThreadHandle thread_handle() const { - return thread_handle_; - } - - /** - * Thread id. - * @return return thread id. - */ - Id thread_id() const { - return Id(thread_handle()); + PlatformThreadHandle thread_handle() const { + return handle_; } /** - * Thread options. + * @brief Thread options. * @return thread options. */ const ThreadOptions& thread_options() const { @@ -199,16 +203,12 @@ class Thread { } /** - * Minimum size of thread stack for specific platform. + * @brief Minimum size of thread stack for specific platform. */ static size_t kMinStackSize; protected: - const std::string name_; - ThreadDelegate* delegate_; - impl::PlatformThreadHandle thread_handle_; - ThreadOptions thread_options_; - volatile unsigned int isThreadRunning_; + sync_primitives::ConditionalVariable state_cond_; private: /** @@ -216,19 +216,17 @@ class Thread { * @param name - display string to identify the thread. * @param delegate - thread procedure delegate. Look for * 'threads/thread_delegate.h' for details. - * NOTE: delegate will be deleted by destructor. + * LifeCycle thread , otherwise it will be joined in stop method + * NOTE: delegate will be deleted after thread will be joined * This constructor made private to prevent * Thread object to be created on stack */ Thread(const char* name, ThreadDelegate* delegate); - + virtual ~Thread(); + static void* threadFunc(void* arg); + static void cleanup(void* arg); DISALLOW_COPY_AND_ASSIGN(Thread); - virtual ~Thread() { } }; -inline bool operator!= (const Thread::Id& left, const Thread::Id& right) { - return !(left == right); -} -std::ostream& operator<<(std::ostream& os, const Thread::Id& thread_id); } // namespace threads #endif // SRC_COMPONENTS_INCLUDE_UTILS_THREADS_THREAD_H_ diff --git a/src/components/include/utils/threads/thread_delegate.h b/src/components/include/utils/threads/thread_delegate.h index 47e68f1e83..66ad30241c 100644 --- a/src/components/include/utils/threads/thread_delegate.h +++ b/src/components/include/utils/threads/thread_delegate.h @@ -35,30 +35,66 @@ #include <pthread.h> +#include "utils/lock.h" + namespace threads { +enum ThreadState { + kInit = 0, + kStarted = 1, + kStopReq = 2 +}; + +class Thread; + /** * Thread procedure interface. * Look for "threads/thread.h" for example */ class ThreadDelegate { - public: + public: + ThreadDelegate() + : state_(kInit), + thread_(NULL) { + } + /** + * \brief Thread procedure. + */ + virtual void threadMain() = 0; + + /** + * Should be called to free all resources allocated in threadMain + * and exiting threadMain + * This function should be blocking and return only when threadMain() will be + * finished in other case segmantation failes are possible + */ + virtual void exitThreadMain(); - /** - * Thread procedure. - */ - virtual void threadMain() = 0; + virtual ~ThreadDelegate(); - /** - * Should be called to free all resources allocated in threadMain - * and exiting threadMain - * This function should be blocking and return only when threadMain() will be - * finished in other case segmantation failes are possible - */ - virtual bool exitThreadMain() { - return false; + Thread* thread() const { + return thread_; + } + + void set_thread(Thread *thread); + + bool ImproveState(unsigned int to) { + state_lock_.Lock(); + if ((state_ + 1 == to) || (to == kInit && state_ == kStopReq)) { + state_ = to; } - virtual ~ThreadDelegate() { } + state_lock_.Unlock(); + return state_ == to; + } + + unsigned int state() const { + return state_; + } + + private: + volatile unsigned int state_; + sync_primitives::SpinMutex state_lock_; + Thread* thread_; }; } // namespace threads diff --git a/src/components/include/utils/threads/thread_options.h b/src/components/include/utils/threads/thread_options.h index 217f0815a9..797ee0693b 100644 --- a/src/components/include/utils/threads/thread_options.h +++ b/src/components/include/utils/threads/thread_options.h @@ -38,7 +38,7 @@ namespace threads { /** - * @breif Startup options for thread. + * @brief Startup options for thread. * Look for "threads/thread.h" for example */ class ThreadOptions { @@ -74,7 +74,7 @@ class ThreadOptions { * @param options - new options. * @return new options. */ - ThreadOptions& operator=(const ThreadOptions& options ) { + ThreadOptions& operator=(const ThreadOptions& options) { stack_size_ = options.stack_size(); is_joinable_ = options.is_joinable(); return *this; diff --git a/src/components/include/utils/timer_thread.h b/src/components/include/utils/timer_thread.h index a3481e4b4b..eaa67effe2 100644 --- a/src/components/include/utils/timer_thread.h +++ b/src/components/include/utils/timer_thread.h @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2013, Ford Motor Company +/* + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,15 +28,16 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. -*/ + */ -#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_TIMER_THREAD -#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_TIMER_THREAD +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_TIMER_THREAD_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_TIMER_THREAD_H_ #include <time.h> #include <inttypes.h> #include <cstdint> #include <limits> +#include <string> #include "utils/conditional_variable.h" #include "utils/lock.h" @@ -52,8 +53,9 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") class TimerDelegate; -/* - * The TimerThread class provide possibility to run timer in a separate thread. +/** + * \class TimerThread + * \brief TimerThread class provide possibility to run timer in a separate thread. * The client should specify callee and const callback function. * Example usage: * @@ -67,315 +69,345 @@ class TimerDelegate; * To stop timer call timer.stop(); * */ -template <class T> +template<class T> class TimerThread { - public: - - friend class TimerDelegate; - friend class TimerLooperDelegate; - + public: + friend class TimerDelegate; + friend class TimerLooperDelegate; + + /** + * @brief Default constructor + * + * @param name - display string to identify the thread. + * @param callee A class that use timer + * @param f CallBackFunction which will be called on timeout + * Attention! "f()" will be called not in main thread but in timer thread + * Never use stop() and start() methods inside f + * @param is_looper Define this timer as looper, + * if true, TimerThread will call "f()" function every time out + * until stop() + */ + TimerThread(const char* name, T* callee, void (T::*f)(), bool is_looper = + false); + + /** + * @brief Destructor + */ + virtual ~TimerThread(); + + /** + * @brief Starts timer for specified timeout. + * Previously started timeout will be set to new value. + * On timeout TimerThread::onTimeOut interface will be called. + * Must not be used in callback function! + * + * @param timeout_seconds Timeout in seconds to be set + */ + virtual void start(uint32_t timeout_seconds); + + /** + * @brief Starts timer for specified timeout. + * Previously started timeout will be set to new value. + * On timeout TimerThread::onTimeOut interface will be called. + * Must not be used in callback function! + * + * @param timeout_seconds Timeout in seconds to be set + * + * @param callee A class that use timer + * + * @param allBackFunction which will be called on timeout + * Attention! "f()" will be called not in main thread but in timer thread + * Never use stop() and start() methods inside f + */ + virtual void start(uint32_t timeout_seconds, T* callee, void (T::*f)()); + + /** + * @brief Stops timer execution + * Must not be used in callback function! + */ + virtual void stop(); + + /** + * @brief Tell timer status + * @return true if timer is currently running, otherwise return false + */ + virtual bool isRunning(); + + /** + * @brief method suspends timer execution + */ + virtual void pause(); + + /** + * @brief Stop timer update timeout and start timer again + * Note that it cancel thread of timer, If you use it from callback, + * it probably will stop execution of callback function + * @param timeout_seconds new timeout value + * + */ + virtual void updateTimeOut(const uint32_t timeout_seconds); + + protected: + /** + * @brief Interface called by delegator on timeout + */ + void onTimeOut() const; + + private: + /** + * @brief Delegate release timer, will call callback function one time + */ + class TimerDelegate : public threads::ThreadDelegate { + public: /** * @brief Default constructor * - * @param name - display string to identify the thread. - * @param callee A class that use timer - * @param f CallBackFunction which will be called on timeout - * Attention! "f()" will be called not in main thread but in timer thread - * Never use stop() and start() methods inside f - * @param is_looper Define this timer as looper, - * if true, TimerThread will call "f()" function every time out - * until stop() + * @param timer_thread The Timer_thread pointer */ - TimerThread(const char* name, T* callee , void (T::*f)(), bool is_looper = false); + explicit TimerDelegate(TimerThread* timer_thread); /** * @brief Destructor */ - virtual ~TimerThread(); + virtual ~TimerDelegate(); /** - * @brief Starts timer for specified timeout. - * Previously started timeout will be set to new value. - * On timeout TimerThread::onTimeOut interface will be called. - * Must not be used in callback function! - * - * @param timeout_seconds Timeout in seconds to be set + * @brief Thread main function. */ - virtual void start(uint32_t timeout_seconds); + virtual void threadMain(); /** - * @brief Stops timer execution - * Must not be used in callback function! + * @brief Called by thread::thread to free all allocated resources. */ - virtual void stop(); + virtual void exitThreadMain(); /** - * @brief Tell tmer status - * @return true if timer is currently running, otherwise return false + * @brief Set new Timeout + * @param timeout_seconds New timeout to be set */ - virtual bool isRunning(); - - /* - * @brief Stop timer update timeout and start timer again - * Note that it cancel thread of timer, If you use it from callback, - * it probably will stop execution of callback function - * @param timeout_seconds new timeout value - * - */ - virtual void updateTimeOut(const uint32_t timeout_seconds); - threads::Thread* thread_; - protected: - - /** - * @brief Interface called by delegator on timeout - */ - void onTimeOut() const; - - private: - + virtual void setTimeOut(const uint32_t timeout_seconds); + + protected: + TimerThread* timer_thread_; + uint32_t timeout_seconds_; + sync_primitives::Lock state_lock_; + sync_primitives::ConditionalVariable termination_condition_; + volatile bool stop_flag_; + int32_t calculateMillisecondsLeft(); + + private: + DISALLOW_COPY_AND_ASSIGN(TimerDelegate); + }; + + /** + * @brief Delegate release looper timer. + * Will call delegate every timeout function while stop() + * won't be called + */ + class TimerLooperDelegate : public TimerDelegate { + public: /** - * @brief Delegate release timer, will call callback function one time + * @brief Default constructor + * + * @param timer_thread The Timer_thread pointer + * @param timeout Timeout to be set */ - class TimerDelegate : public threads::ThreadDelegate { - public: - - /** - * @brief Default constructor - * - * @param timer_thread The Timer_thread pointer - */ - TimerDelegate(TimerThread* timer_thread); - - /** - * @brief Destructor - */ - virtual ~TimerDelegate(); - - /** - * @brief Thread main function. - */ - virtual void threadMain(); - - /** - * @brief Called by thread::thread to free all allocated resources. - */ - virtual bool exitThreadMain(); - - /** - * @brief Set new Timeout - * @param timeout_seconds New timeout to be set - */ - virtual void setTimeOut(const uint32_t timeout_seconds); - - protected: - TimerThread* timer_thread_; - uint32_t timeout_seconds_; - sync_primitives::Lock state_lock_; - sync_primitives::ConditionalVariable termination_condition_; - volatile bool stop_flag_; - int32_t calculateMillisecondsLeft(); - private: - DISALLOW_COPY_AND_ASSIGN(TimerDelegate); - }; - + explicit TimerLooperDelegate(TimerThread* timer_thread); /** - * @brief Delegate release looper timer. - * Will call delegate every timeout function while stop() - * won't be called + * @brief Thread main function. */ - class TimerLooperDelegate : public TimerDelegate { - public: - - /** - * @brief Default constructor - * - * @param timer_thread The Timer_thread pointer - * @param timeout Timeout to be set - */ - TimerLooperDelegate(TimerThread* timer_thread); - - /** - * @brief Thread main function. - */ - virtual void threadMain(); - private: - DISALLOW_COPY_AND_ASSIGN(TimerLooperDelegate); - }; - void (T::*callback_)(); - T* callee_; - TimerDelegate* delegate_; - //threads::Thread* thread_; - std::string name_; - mutable bool is_running_; - bool is_looper_; - - DISALLOW_COPY_AND_ASSIGN(TimerThread); + virtual void threadMain(); + + private: + DISALLOW_COPY_AND_ASSIGN(TimerLooperDelegate); + }; + threads::Thread* thread_; + void (T::*callback_)(); + T* callee_; + TimerDelegate* delegate_; + std::string name_; + volatile bool is_looper_; + + DISALLOW_COPY_AND_ASSIGN(TimerThread); }; -template <class T> -TimerThread<T>::TimerThread(const char* name, T* callee, void (T::*f)(), bool is_looper) - : thread_(NULL), - callback_(f), - callee_(callee), - delegate_(NULL), - is_running_(false), - is_looper_(is_looper) { +template<class T> +TimerThread<T>::TimerThread(const char* name, T* callee, void (T::*f)(), + bool is_looper) + : thread_(NULL), + callback_(f), + callee_(callee), + delegate_(NULL), + name_(name), + is_looper_(is_looper) { + delegate_ = + is_looper_ ? new TimerLooperDelegate(this) : new TimerDelegate(this); + + thread_ = threads::CreateThread(name_.c_str(), delegate_); } -template <class T> +template<class T> TimerThread<T>::~TimerThread() { - LOG4CXX_INFO(logger_, "TimerThread is to destroy " << name_); - stop(); + LOG4CXX_DEBUG(logger_, "TimerThread is to be destroyed " << name_); + thread_->join(); + delete delegate_; + threads::DeleteThread(thread_); callback_ = NULL; callee_ = NULL; } -template <class T> +template<class T> void TimerThread<T>::start(uint32_t timeout_seconds) { - LOG4CXX_TRACE(logger_, "Starting timer " << this); - if (is_running_) { + LOG4CXX_AUTO_TRACE(logger_); + if (isRunning()) { LOG4CXX_INFO(logger_, "TimerThread start needs stop " << name_); stop(); } + updateTimeOut(timeout_seconds); + thread_->start(); +} - delegate_ = is_looper_ ? - new TimerLooperDelegate(this) : - new TimerDelegate(this); - delegate_->setTimeOut(timeout_seconds); - - thread_ = threads::CreateThread("TimerThread", delegate_); - if (delegate_ && thread_) { - is_running_ = true; - thread_->start(); - } +template<class T> +void TimerThread<T>::start(uint32_t timeout_seconds, T* callee, + void (T::*f)()) { + callee_ = callee; + callback_ = f; + start(timeout_seconds); } -template <class T> +template<class T> void TimerThread<T>::stop() { - LOG4CXX_TRACE(logger_, "Stopping timer " << this); - if (is_running_ && delegate_ && thread_) { - LOG4CXX_INFO(logger_, "TimerThread thread_ stop " << name_); - thread_->stop(); - is_running_ = false; - } else { - LOG4CXX_INFO(logger_, "TimerThread thread_ not stop " << name_); - } + LOG4CXX_AUTO_TRACE(logger_); + DCHECK(thread_); + LOG4CXX_DEBUG(logger_, "Stopping timer " << name_); + thread_->join(); } -template <class T> +template<class T> bool TimerThread<T>::isRunning() { - return is_running_; + DCHECK(thread_); + return thread_->is_running(); +} + +template<class T> +void TimerThread<T>::pause() { + LOG4CXX_DEBUG(logger_, "Suspension of timer " << name_); + const uint32_t wait_seconds = std::numeric_limits<uint32_t>::max(); + updateTimeOut(wait_seconds); } -template <class T> +template<class T> void TimerThread<T>::updateTimeOut(const uint32_t timeout_seconds) { delegate_->setTimeOut(timeout_seconds); } -template <class T> -void TimerThread<T>::onTimeOut() const { +template<class T> void TimerThread<T>::onTimeOut() const { if (callee_ && callback_) { (callee_->*callback_)(); - /* - if (!is_looper_) { - stop(); - } - */ } } -template <class T> +template<class T> TimerThread<T>::TimerDelegate::TimerDelegate(TimerThread* timer_thread) - : timer_thread_(timer_thread), - timeout_seconds_(0), - state_lock_(true), - stop_flag_(false) { + : timer_thread_(timer_thread), + timeout_seconds_(0), + state_lock_(true), + stop_flag_(false) { DCHECK(timer_thread_); } -template <class T> -TimerThread<T>::TimerLooperDelegate::TimerLooperDelegate(TimerThread* timer_thread) - : TimerDelegate(timer_thread) { +template<class T> +TimerThread<T>::TimerLooperDelegate::TimerLooperDelegate( + TimerThread* timer_thread) + : TimerDelegate(timer_thread) { } -template <class T> +template<class T> TimerThread<T>::TimerDelegate::~TimerDelegate() { timer_thread_ = NULL; } -template <class T> +template<class T> void TimerThread<T>::TimerDelegate::threadMain() { using sync_primitives::ConditionalVariable; sync_primitives::AutoLock auto_lock(state_lock_); + stop_flag_ = false; while (!stop_flag_) { // Sleep - int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft(); + int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft(); ConditionalVariable::WaitStatus wait_status = termination_condition_.WaitFor(auto_lock, wait_milliseconds_left); // Quit sleeping or continue sleeping in case of spurious wake up - if (ConditionalVariable::kTimeout == wait_status || - wait_milliseconds_left <= 0) { - break; + if (ConditionalVariable::kTimeout == wait_status + || wait_milliseconds_left <= 0) { + LOG4CXX_TRACE(logger_, + "Timer timeout " << wait_milliseconds_left << " ms"); + timer_thread_->onTimeOut(); + return; + } else { + LOG4CXX_DEBUG(logger_, + "Timeout reset force: " << TimerDelegate::timeout_seconds_); + return; } } - if (!stop_flag_) { - timer_thread_->onTimeOut(); - timer_thread_->stop(); - } } -template <class T> +template<class T> void TimerThread<T>::TimerLooperDelegate::threadMain() { using sync_primitives::ConditionalVariable; sync_primitives::AutoLock auto_lock(TimerDelegate::state_lock_); + TimerDelegate::stop_flag_ = false; while (!TimerDelegate::stop_flag_) { - int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft(); + int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft(); ConditionalVariable::WaitStatus wait_status = - TimerDelegate::termination_condition_.WaitFor(auto_lock, wait_milliseconds_left); + TimerDelegate::termination_condition_.WaitFor(auto_lock, + wait_milliseconds_left); // Quit sleeping or continue sleeping in case of spurious wake up - if (ConditionalVariable::kTimeout == wait_status || - wait_milliseconds_left <= 0) { - LOG4CXX_TRACE(logger_, "Timer timeout " << wait_milliseconds_left); + if (ConditionalVariable::kTimeout == wait_status + || wait_milliseconds_left <= 0) { + LOG4CXX_TRACE(logger_, + "Timer timeout " << wait_milliseconds_left << " ms"); TimerDelegate::timer_thread_->onTimeOut(); } else { - LOG4CXX_DEBUG(logger_, "Timeout reset force: " << TimerDelegate::timeout_seconds_); + LOG4CXX_DEBUG(logger_, + "Timeout reset force: " << TimerDelegate::timeout_seconds_); } } } - -template <class T> -bool TimerThread<T>::TimerDelegate::exitThreadMain() { +template<class T> +void TimerThread<T>::TimerDelegate::exitThreadMain() { sync_primitives::AutoLock auto_lock(state_lock_); stop_flag_ = true; termination_condition_.NotifyOne(); - return true; } -template <class T> +template<class T> void TimerThread<T>::TimerDelegate::setTimeOut(const uint32_t timeout_seconds) { timeout_seconds_ = timeout_seconds; termination_condition_.NotifyOne(); } -template <class T> +template<class T> int32_t TimerThread<T>::TimerThread::TimerDelegate::calculateMillisecondsLeft() { time_t cur_time = time(NULL); time_t end_time = std::numeric_limits<time_t>::max(); - if (TimerDelegate::timeout_seconds_ + cur_time > TimerDelegate::timeout_seconds_) { // no overflow occurred + if (TimerDelegate::timeout_seconds_ + cur_time + > TimerDelegate::timeout_seconds_) { // no overflow occurred end_time = cur_time + TimerDelegate::timeout_seconds_; } - int64_t wait_seconds_left = static_cast<int64_t>(difftime(end_time, cur_time)); - int32_t wait_milliseconds_left = std::numeric_limits<int32_t>::max(); - const int32_t millisecconds_in_second = 1000; - if (wait_seconds_left < std::numeric_limits<int32_t>::max() / millisecconds_in_second) { - wait_milliseconds_left = millisecconds_in_second * wait_seconds_left; + int64_t wait_seconds_left = static_cast<int64_t>(difftime(end_time, cur_time)); + int32_t wait_milliseconds_left = std::numeric_limits<int32_t>::max(); + const int32_t milliseconds_in_second = 1000; + if (wait_seconds_left + < std::numeric_limits<int32_t>::max() / milliseconds_in_second) { + wait_milliseconds_left = milliseconds_in_second * wait_seconds_left; } return wait_milliseconds_left; } } // namespace timer -#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_TIMER_THREAD +#endif // SRC_COMPONENTS_INCLUDE_UTILS_TIMER_THREAD_H_ |