diff options
Diffstat (limited to 'src/components/utils')
34 files changed, 950 insertions, 299 deletions
diff --git a/src/components/utils/CMakeLists.txt b/src/components/utils/CMakeLists.txt index bbb74dc1e1..79347f4d9f 100644 --- a/src/components/utils/CMakeLists.txt +++ b/src/components/utils/CMakeLists.txt @@ -13,8 +13,9 @@ set (SOURCES ./src/conditional_variable_posix.cc ./src/file_system.cc ./src/threads/posix_thread.cc - ./src/threads/thread_manager.cc + ./src/threads/thread_delegate.cc ./src/threads/thread_validator.cc + ./src/threads/async_runner.cc ./src/lock_posix.cc ./src/rwlock_posix.cc ./src/date_time.cc @@ -26,9 +27,11 @@ set (SOURCES if(ENABLE_LOG) list(APPEND SOURCES + ./src/logger.cc ./src/push_log.cc ./src/log_message_loop_thread.cc ./src/logger_status.cc + ./src/auto_trace.cc ) endif() diff --git a/src/components/utils/include/utils/back_trace.h b/src/components/utils/include/utils/back_trace.h index 7f8912faf9..f2410e36bc 100644 --- a/src/components/utils/include/utils/back_trace.h +++ b/src/components/utils/include/utils/back_trace.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -61,10 +61,10 @@ class Backtrace { // Captured symbols in order from topmost stack frame to last captured std::vector<std::string> CallStack() const; - threads::Thread::Id ThreadId() const; + threads::PlatformThreadHandle ThreadId() const; private: - threads::Thread::Id thread_id_; + threads::PlatformThreadHandle thread_id_; std::vector<void*> backtrace_; }; diff --git a/src/components/utils/include/utils/bitstream.h b/src/components/utils/include/utils/bitstream.h index cba15abd8b..9bf41d187f 100644 --- a/src/components/utils/include/utils/bitstream.h +++ b/src/components/utils/include/utils/bitstream.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/include/utils/file_system.h b/src/components/utils/include/utils/file_system.h index d68ec484f9..4340158467 100644 --- a/src/components/utils/include/utils/file_system.h +++ b/src/components/utils/include/utils/file_system.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/include/utils/log_message_loop_thread.h b/src/components/utils/include/utils/log_message_loop_thread.h index b23a246e13..87b6c7e531 100644 --- a/src/components/utils/include/utils/log_message_loop_thread.h +++ b/src/components/utils/include/utils/log_message_loop_thread.h @@ -37,6 +37,7 @@ #include <queue> #include <log4cxx/logger.h> +#include "utils/macro.h" #include "utils/threads/message_loop_thread.h" #include "utils/singleton.h" diff --git a/src/components/utils/include/utils/resource_usage.h b/src/components/utils/include/utils/resource_usage.h index a8fa4aa7d9..1f1a58b47c 100644 --- a/src/components/utils/include/utils/resource_usage.h +++ b/src/components/utils/include/utils/resource_usage.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/include/utils/signals.h b/src/components/utils/include/utils/signals.h index 28e8afd9d6..6c91836309 100644 --- a/src/components/utils/include/utils/signals.h +++ b/src/components/utils/include/utils/signals.h @@ -1,41 +1,49 @@ /* -* 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_UTILS_INCLUDE_UTILS_SIGNALS_H_ #define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SIGNALS_H_ +#ifdef __QNXNTO__ +typedef void (*sighandler_t) (int); +#else +#include <signal.h> +#endif + namespace utils { -bool SubscribeToTerminateSignal(void (*func)(int32_t p)); -bool ResetSubscribeToTerminateSignal(); + +bool SubscribeToTerminateSignal(sighandler_t func); +bool SubscribeToFaultSignal(sighandler_t func); + } // namespace utils #endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SIGNALS_H_ diff --git a/src/components/utils/include/utils/singleton.h b/src/components/utils/include/utils/singleton.h index d7b625e0a1..41face4f2f 100644 --- a/src/components/utils/include/utils/singleton.h +++ b/src/components/utils/include/utils/singleton.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_SINGLETON_H_ #define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_ diff --git a/src/components/utils/include/utils/stl_utils.h b/src/components/utils/include/utils/stl_utils.h index f525c6429f..afab995857 100644 --- a/src/components/utils/include/utils/stl_utils.h +++ b/src/components/utils/include/utils/stl_utils.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/include/utils/system.h b/src/components/utils/include/utils/system.h index 16bdc03673..f04a5780ca 100644 --- a/src/components/utils/include/utils/system.h +++ b/src/components/utils/include/utils/system.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/include/utils/threads/pulse_thread_delegate.h b/src/components/utils/include/utils/threads/pulse_thread_delegate.h index bb109bde94..207b64caaf 100644 --- a/src/components/utils/include/utils/threads/pulse_thread_delegate.h +++ b/src/components/utils/include/utils/threads/pulse_thread_delegate.h @@ -57,7 +57,7 @@ class PulseThreadDelegate : public ThreadDelegate { */ PulseThreadDelegate(); virtual void threadMain(); - virtual bool exitThreadMain(); + virtual void exitThreadMain(); protected: /** @@ -86,7 +86,7 @@ class PulseThreadDelegate : public ThreadDelegate { private: enum {PULSE_CODE = _PULSE_CODE_MINAVAIL + 1}; - bool run_; + volatile bool run_; int chid_; int coid_; }; diff --git a/src/components/utils/include/utils/threads/thread_manager.h b/src/components/utils/include/utils/threads/thread_manager.h index d72abb428f..38fecb58a2 100644 --- a/src/components/utils/include/utils/threads/thread_manager.h +++ b/src/components/utils/include/utils/threads/thread_manager.h @@ -63,12 +63,7 @@ namespace threads { */ class ThreadManager : public utils::Singleton<ThreadManager> { public: - struct ThreadDesc { - pthread_t handle; - ThreadDelegate* delegate; - }; ThreadManager() {} - MessageQueue<ThreadDesc> threads_to_terminate; private: DISALLOW_COPY_AND_ASSIGN(ThreadManager); diff --git a/src/components/utils/include/utils/threads/thread_validator.h b/src/components/utils/include/utils/threads/thread_validator.h index def1994b76..214b96c3e5 100644 --- a/src/components/utils/include/utils/threads/thread_validator.h +++ b/src/components/utils/include/utils/threads/thread_validator.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -68,7 +68,7 @@ class SingleThreadSimpleValidator { // of classes being checked for absence of concurrent access void AssertRunningOnCreationThread() const; private: - const Thread::Id creation_thread_id_; + const PlatformThreadHandle creation_thread_id_; }; @@ -91,13 +91,13 @@ class SingleThreadValidator { // Must be called prior to transferring object being validated to // another thread or when passing it back - void PassToThread(Thread::Id thread_id) const; + void PassToThread(PlatformThreadHandle thread_id) const; // This method should be called in every public method // of classes being checked for absence of unintended concurrent // access void AssertRunningOnValidThread() const; private: - mutable Thread::Id owning_thread_id_; + mutable PlatformThreadHandle owning_thread_id_; }; } // namespace threads diff --git a/src/components/utils/src/appenders_loader.cc b/src/components/utils/src/appenders_loader.cc index cbbd039060..9741bd1b8d 100644 --- a/src/components/utils/src/appenders_loader.cc +++ b/src/components/utils/src/appenders_loader.cc @@ -39,7 +39,7 @@ namespace utils { AppendersLoader appenders_loader; AppendersLoader::AppendersLoader() { - handle_ = dlopen("libappenders.so", RTLD_LAZY | RTLD_NODELETE); + handle_ = dlopen("libappenders.so", RTLD_LAZY); } AppendersLoader::~AppendersLoader() { diff --git a/src/components/utils/src/auto_trace.cc b/src/components/utils/src/auto_trace.cc new file mode 100644 index 0000000000..5104851a51 --- /dev/null +++ b/src/components/utils/src/auto_trace.cc @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#include <apr_time.h> +#include <log4cxx/spi/loggingevent.h> + +#include "utils/auto_trace.h" +#include "utils/push_log.h" + +namespace logger { + +AutoTrace::AutoTrace( + log4cxx::LoggerPtr logger, + const log4cxx::spi::LocationInfo& location) : + logger_(logger), location_(location) { + if (logger_->isTraceEnabled()) { + push_log(logger_, + ::log4cxx::Level::getTrace(), + "Enter", + apr_time_now(), + location_, + ::log4cxx::spi::LoggingEvent::getCurrentThreadName() + ); + } +} + +AutoTrace::~AutoTrace() { + if (logger_->isTraceEnabled()) { + push_log(logger_, + ::log4cxx::Level::getTrace(), + "Exit", + apr_time_now(), + location_, // the location corresponds rather to creation of autotrace object than to deletion + ::log4cxx::spi::LoggingEvent::getCurrentThreadName() + ); + } +} + +} // namespace logger diff --git a/src/components/utils/src/back_trace.cc b/src/components/utils/src/back_trace.cc index 23b1b4d1e9..f49c60b467 100644 --- a/src/components/utils/src/back_trace.cc +++ b/src/components/utils/src/back_trace.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -89,7 +89,7 @@ vector<string> Backtrace::CallStack() const { return callstack; } -Thread::Id Backtrace::ThreadId() const { +threads::PlatformThreadHandle Backtrace::ThreadId() const { return thread_id_; } diff --git a/src/components/utils/src/bitstream.cc b/src/components/utils/src/bitstream.cc index c616b1ae4a..ae353b44c6 100644 --- a/src/components/utils/src/bitstream.cc +++ b/src/components/utils/src/bitstream.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/src/conditional_variable_posix.cc b/src/components/utils/src/conditional_variable_posix.cc index a89f8cab65..9efae01c53 100644 --- a/src/components/utils/src/conditional_variable_posix.cc +++ b/src/components/utils/src/conditional_variable_posix.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -83,6 +83,15 @@ void ConditionalVariable::Broadcast() { } +void ConditionalVariable::Wait(Lock& lock) { + lock.AssertTakenAndMarkFree(); + int32_t wait_status = pthread_cond_wait(&cond_var_, + &lock.mutex_); + lock.AssertFreeAndMarkTaken(); + if (wait_status != 0) + LOG4CXX_ERROR(logger_, "Failed to wait for conditional variable"); +} + void ConditionalVariable::Wait(AutoLock& auto_lock) { Lock& lock = auto_lock.GetLock(); lock.AssertTakenAndMarkFree(); diff --git a/src/components/utils/src/date_time.cc b/src/components/utils/src/date_time.cc index f190951647..6185bd0480 100644 --- a/src/components/utils/src/date_time.cc +++ b/src/components/utils/src/date_time.cc @@ -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. + */ #include <sys/time.h> #include <stdint.h> @@ -100,3 +100,11 @@ TimeCompare date_time::DateTime::compareTime(const TimevalStruct &time1, const T } } // namespace date_time + +bool operator<(const TimevalStruct& time1, const TimevalStruct& time2) { + return date_time::DateTime::Less(time1, time2); +} + +bool operator==(const TimevalStruct& time1, const TimevalStruct& time2) { + return date_time::DateTime::Equal(time1, time2); +} diff --git a/src/components/utils/src/file_system.cc b/src/components/utils/src/file_system.cc index 64e021a6f1..cb01e4c561 100644 --- a/src/components/utils/src/file_system.cc +++ b/src/components/utils/src/file_system.cc @@ -325,10 +325,12 @@ std::vector<std::string> file_system::ListFiles( } closedir(directory); + + } + #ifdef __QNXNTO__ - delete[] direntbuffer; + delete[] direntbuffer; #endif - } return listFiles; } diff --git a/src/components/utils/src/lock_posix.cc b/src/components/utils/src/lock_posix.cc index f75b7ee9ea..4048b7d939 100644 --- a/src/components/utils/src/lock_posix.cc +++ b/src/components/utils/src/lock_posix.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -34,6 +34,8 @@ #include <errno.h> #include <stdint.h> +#include <stdio.h> +#include <string.h> #include "utils/logger.h" @@ -47,7 +49,7 @@ Lock::Lock() is_mutex_recursive_(false) #endif // NDEBUG { - int32_t status = pthread_mutex_init(&mutex_, NULL); + const int32_t status = pthread_mutex_init(&mutex_, NULL); if (status != 0) { LOG4CXX_ERROR(logger_, "Failed to initialize mutex"); } @@ -79,54 +81,29 @@ Lock::Lock(bool is_mutex_recursive) Lock::~Lock() { #ifndef NDEBUG if (lock_taken_ > 0) { - LOG4CXX_ERROR(logger_, "Destroying non-released mutex"); + LOG4CXX_ERROR(logger_, "Destroying non-released mutex " << &mutex_); } #endif int32_t status = pthread_mutex_destroy(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to destroy mutex"); - } + LOG4CXX_ERROR(logger_, "Failed to destroy mutex " << &mutex_ << ": " << strerror(status)); } } void Lock::Acquire() { int32_t status = pthread_mutex_lock(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to acquire mutex"); + LOG4CXX_ERROR(logger_, "Failed to acquire mutex " << &mutex_ << ": " << strerror(status)); + } else { + AssertFreeAndMarkTaken(); } - AssertFreeAndMarkTaken(); } void Lock::Release() { AssertTakenAndMarkFree(); int32_t status = pthread_mutex_unlock(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to unlock mutex"); - } -} - -bool Lock::Try() { - bool ackquired = false; -#ifndef NDEBUG - if ((lock_taken_ > 0) && !is_mutex_recursive_) { - LOG4CXX_ERROR(logger_, "Trying to lock already taken not recurcive mutex"); - } -#endif - switch(pthread_mutex_trylock(&mutex_)) { - case 0: { - ackquired = true; -#ifndef NDEBUG - lock_taken_++; -#endif - } break; - case EBUSY: { - ackquired = false; - } break; - default: { - ackquired = false; - LOG4CXX_ERROR(logger_, "Failed to try lock the mutex"); - } + LOG4CXX_ERROR(logger_, "Failed to unlock mutex" << &mutex_ << ": " << strerror(status)); } - return ackquired; } #ifndef NDEBUG diff --git a/src/components/utils/src/logger.cc b/src/components/utils/src/logger.cc new file mode 100644 index 0000000000..72c85424d3 --- /dev/null +++ b/src/components/utils/src/logger.cc @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#include "utils/logger.h" +#include "utils/log_message_loop_thread.h" +#include <apr_time.h> + +void deinit_logger () { + CREATE_LOGGERPTR_LOCAL (logger_, "Logger"); + LOG4CXX_DEBUG(logger_, "Logger deinitialization"); + logger::LogMessageLoopThread::destroy(); + log4cxx::LoggerPtr rootLogger = log4cxx::Logger::getRootLogger(); + log4cxx::spi::LoggerRepositoryPtr repository = rootLogger->getLoggerRepository(); + log4cxx::LoggerList loggers = repository->getCurrentLoggers(); + for (log4cxx::LoggerList::iterator i = loggers.begin(); i != loggers.end(); ++i) { + log4cxx::LoggerPtr logger = *i; + logger->removeAllAppenders(); + } + rootLogger->removeAllAppenders(); +} + +log4cxx_time_t time_now() { + return apr_time_now(); +} diff --git a/src/components/utils/src/logger_status.cc b/src/components/utils/src/logger_status.cc index be341b9add..ea9dfa3f22 100644 --- a/src/components/utils/src/logger_status.cc +++ b/src/components/utils/src/logger_status.cc @@ -34,6 +34,6 @@ namespace logger { -LoggerStatus logger_status = LoggerThreadNotCreated; +volatile LoggerStatus logger_status = LoggerThreadNotCreated; } // namespace logger diff --git a/src/components/utils/src/resource_usage.cc b/src/components/utils/src/resource_usage.cc index aaa9c1b4a7..62c8d25b82 100644 --- a/src/components/utils/src/resource_usage.cc +++ b/src/components/utils/src/resource_usage.cc @@ -124,6 +124,8 @@ bool Resources::GetProcInfo(Resources::PidStats& output) { if (0 >= fd) { LOG4CXX_ERROR(logger_, "Failed open process proc file : " << GetProcPath() << "; error no : " << strerror( errno ) ); + + close(fd); return false; } devctl(fd, DCMD_PROC_INFO, &output, sizeof(output), 0); @@ -148,14 +150,14 @@ bool Resources::GetMemInfo(Resources::MemInfo &output) { std::string as_path = GetStatPath(); struct stat st; struct _dir* proc_dir = 0; - struct dirent* proc_entry = 0; if (0 == (proc_dir = opendir(proc))) { LOG4CXX_ERROR(logger_, "Unable to access to " << proc); result = false; return result; } - if (0 == (proc_entry = readdir(proc_dir))) { + if (0 == readdir(proc_dir)) { LOG4CXX_ERROR(logger_, "Unable to read : " << proc_dir); + closedir(proc_dir); result = false; return result; } diff --git a/src/components/utils/src/signals_linux.cc b/src/components/utils/src/signals_linux.cc index 3ded6a5877..2e598d1b0f 100644 --- a/src/components/utils/src/signals_linux.cc +++ b/src/components/utils/src/signals_linux.cc @@ -1,54 +1,63 @@ /* -* 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. + */ #include <csignal> #include <cstdlib> #include <stdint.h> +#include "utils/signals.h" + namespace utils { -bool SubscribeToTerminateSignal(void (*func)(int32_t p)) { +bool SubscribeToTerminateSignal(sighandler_t func) { struct sigaction act; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; - return (sigaction(SIGINT, &act, NULL) == 0) - && (sigaction(SIGTERM, &act, NULL) == 0); + bool sigint_subscribed = (sigaction(SIGINT, &act, NULL) == 0); + bool sigterm_subscribed = (sigaction(SIGTERM, &act, NULL) == 0); + + return sigint_subscribed && sigterm_subscribed; } -bool ResetSubscribeToTerminateSignal() { - void (*prev_func)(int32_t p); - prev_func = signal(SIGINT, SIG_DFL); - return (SIG_ERR != prev_func); +bool SubscribeToFaultSignal(sighandler_t func) { + struct sigaction act; + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESETHAND; // we only want to catch SIGSEGV once to flush logger queue + + bool sigsegv_subscribed = (sigaction(SIGSEGV, &act, NULL) == 0); + + return sigsegv_subscribed; } } // namespace utils diff --git a/src/components/utils/src/system.cc b/src/components/utils/src/system.cc index ee90315db0..c48539b054 100644 --- a/src/components/utils/src/system.cc +++ b/src/components/utils/src/system.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/src/threads/async_runner.cc b/src/components/utils/src/threads/async_runner.cc new file mode 100644 index 0000000000..4a00317911 --- /dev/null +++ b/src/components/utils/src/threads/async_runner.cc @@ -0,0 +1,116 @@ +/* + 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. + */ + +#include "utils/threads/async_runner.h" + +#include <string> + +#include "utils/logger.h" + +namespace threads { + +CREATE_LOGGERPTR_GLOBAL(logger_, "AsyncRunner"); + +AsyncRunner::AsyncRunner(const std::string &thread_name) + : executor_(new AsyncRunnerDelegate) { + LOG4CXX_AUTO_TRACE(logger_); + thread_ = threads::CreateThread(thread_name.c_str(), + executor_); + thread_->start(); +} + +void AsyncRunner::AsyncRun(ThreadDelegate* delegate) { + LOG4CXX_AUTO_TRACE(logger_); + executor_->runDelegate(delegate); +} + +void AsyncRunner::Stop() { + LOG4CXX_AUTO_TRACE(logger_); + thread_->join(); +} + +AsyncRunner::~AsyncRunner() { + LOG4CXX_AUTO_TRACE(logger_); + thread_->join(); + delete executor_; + threads::DeleteThread(thread_); +} + +AsyncRunner::AsyncRunnerDelegate::AsyncRunnerDelegate() + : stop_flag_(false) { +} + +void AsyncRunner::AsyncRunnerDelegate::processDelegate() { + if (!delegates_queue_.empty()) { + delegates_queue_lock_.Acquire(); + ThreadDelegate* run = delegates_queue_.front(); + delegates_queue_.pop(); + delegates_queue_lock_.Release(); + + if (NULL != run) { + run->threadMain(); + delete run; + } + } +} + +void AsyncRunner::AsyncRunnerDelegate::waitForDelegate() { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(delegates_queue_lock_); + if (!stop_flag_ && delegates_queue_.empty()) { + delegate_notifier_.Wait(lock); + } +} + +void AsyncRunner::AsyncRunnerDelegate::threadMain() { + LOG4CXX_AUTO_TRACE(logger_); + while (!stop_flag_) { + processDelegate(); + waitForDelegate(); + } +} + +void AsyncRunner::AsyncRunnerDelegate::exitThreadMain() { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(delegates_queue_lock_); + stop_flag_ = true; + delegate_notifier_.NotifyOne(); +} + +void AsyncRunner::AsyncRunnerDelegate::runDelegate(ThreadDelegate* delegate) { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(delegates_queue_lock_); + delegates_queue_.push(delegate); + delegate_notifier_.NotifyOne(); +} + +} // namespace policy. diff --git a/src/components/utils/src/threads/posix_thread.cc b/src/components/utils/src/threads/posix_thread.cc index 3f7e006eca..76cc5800e0 100644 --- a/src/components/utils/src/threads/posix_thread.cc +++ b/src/components/utils/src/threads/posix_thread.cc @@ -30,19 +30,21 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "utils/threads/thread.h" + #include <errno.h> #include <limits.h> #include <stddef.h> #include <signal.h> +#include <unistd.h> #include "utils/atomic.h" -#include "utils/threads/thread.h" +#include "utils/threads/thread_delegate.h" #include "utils/threads/thread_manager.h" #include "utils/logger.h" #include "pthread.h" - #ifndef __QNXNTO__ const int EOK = 0; #endif @@ -55,50 +57,75 @@ namespace threads { CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") -namespace { - -static void* threadFunc(void* arg) { - LOG4CXX_INFO(logger_, "Thread #" << pthread_self() << " started successfully"); - threads::Thread* thread = static_cast<threads::Thread*>(arg); - threads::ThreadDelegate* delegate = thread->delegate(); - delegate->threadMain(); - thread->set_running(false); - MessageQueue<ThreadManager::ThreadDesc>& threads = ::threads::ThreadManager::instance()->threads_to_terminate; - if (!threads.IsShuttingDown()) { - LOG4CXX_INFO(logger_, "Pushing thread #" << pthread_self() << " to join queue"); - ThreadManager::ThreadDesc desc = { pthread_self(), delegate }; - threads.push(desc); - } - LOG4CXX_INFO(logger_, "Thread #" << pthread_self() << " exited successfully"); - return NULL; -} +size_t Thread::kMinStackSize = PTHREAD_STACK_MIN; /* Ubuntu : 16384 ; QNX : 256; */ +void Thread::cleanup(void* arg) { + LOG4CXX_AUTO_TRACE(logger_); + Thread* thread = reinterpret_cast<Thread*>(arg); + sync_primitives::AutoLock auto_lock(thread->state_lock_); + thread->isThreadRunning_ = false; + thread->state_cond_.Broadcast(); } -size_t Thread::kMinStackSize = PTHREAD_STACK_MIN; /* Ubuntu : 16384 ; QNX : 256; */ - -/* -void ThreadBase::set_name(const std::string name) { - std::string trimname = name.erase(15); - if(pthread_setname_np(thread_handle_, trimname.c_str()) != EOK) { - LOG4CXX_WARN(logger_, "Couldn't set pthread name \"" - << trimname - << "\", error code " - << pthread_result - << " (" - << strerror(pthread_result) - << ")"); +void* Thread::threadFunc(void* arg) { + // 0 - state_lock unlocked + // stopped = 0 + // running = 0 + // finalized = 0 + // 4 - state_lock unlocked + // stopped = 1 + // running = 1 + // finalized = 0 + // 5 - state_lock unlocked + // stopped = 1 + // running = 1 + // finalized = 1 + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + LOG4CXX_DEBUG(logger_, "Thread #" << pthread_self() << " started successfully"); + + threads::Thread* thread = reinterpret_cast<Thread*>(arg); + DCHECK(thread); + + pthread_cleanup_push(&cleanup, thread); + + thread->state_lock_.Acquire(); + thread->state_cond_.Broadcast(); + + while (!thread->finalized_) { + LOG4CXX_DEBUG(logger_, "Thread #" << pthread_self() << " iteration"); + thread->run_cond_.Wait(thread->state_lock_); + LOG4CXX_DEBUG(logger_, "Thread #" << pthread_self() << " execute. " + << "stopped_ = " << thread->stopped_ << "; finalized_ = " << thread->finalized_); + if (!thread->stopped_ && !thread->finalized_) { + thread->isThreadRunning_ = true; + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + thread->state_lock_.Release(); + thread->delegate_->threadMain(); + thread->state_lock_.Acquire(); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + thread->isThreadRunning_ = false; + } + thread->state_cond_.Broadcast(); + LOG4CXX_DEBUG(logger_, "Thread #" << pthread_self() << " finished iteration"); } + + thread->state_lock_.Release(); + pthread_cleanup_pop(1); + + LOG4CXX_DEBUG(logger_, "Thread #" << pthread_self() << " exited successfully"); + return NULL; } -*/ -void Thread::SetNameForId(const Id& thread_id, const std::string& name) { - std::string nm = name; - std::string& trimname = nm.size() > 15 ? nm.erase(15) : nm; - const int rc = pthread_setname_np(thread_id.id_, trimname.c_str()); - if(rc == EOK) { +void Thread::SetNameForId(const PlatformThreadHandle& thread_id, std::string name) { + if (name.size() > THREAD_NAME_SIZE) + name.erase(THREAD_NAME_SIZE); + const int rc = pthread_setname_np(thread_id, name.c_str()); + if(rc != EOK) { LOG4CXX_WARN(logger_, "Couldn't set pthread name \"" - << trimname + << name << "\", error code " << rc << " (" @@ -110,46 +137,61 @@ void Thread::SetNameForId(const Id& thread_id, const std::string& name) { Thread::Thread(const char* name, ThreadDelegate* delegate) : name_(name ? name : "undefined"), delegate_(delegate), - thread_handle_(0), + handle_(0), thread_options_(), - isThreadRunning_(0) { -} + isThreadRunning_(0), + stopped_(false), + finalized_(false), + thread_created_(false) { } -ThreadDelegate* Thread::delegate() const { - return delegate_; +bool Thread::start() { + return start(thread_options_); } -bool Thread::start() { - return startWithOptions(thread_options_); +PlatformThreadHandle Thread::CurrentId() { + return pthread_self(); } -Thread::Id Thread::CurrentId() { - return Id(pthread_self()); +void Thread::WaitForRun() { + sync_primitives::AutoLock auto_lock(state_lock_); + run_cond_.Wait(auto_lock); } -bool Thread::startWithOptions(const ThreadOptions& options) { - LOG4CXX_TRACE_ENTER(logger_); +bool Thread::start(const ThreadOptions& options) { + LOG4CXX_AUTO_TRACE(logger_); + + sync_primitives::AutoLock auto_lock(state_lock_); + // 1 - state_lock locked + // stopped = 0 + // running = 0 + if (!delegate_) { - NOTREACHED(); - LOG4CXX_ERROR(logger_, "NULL delegate"); - LOG4CXX_TRACE_EXIT(logger_); + LOG4CXX_ERROR(logger_, "Cannot start thread" << name_ + << ": delegate is NULL"); + // 0 - state_lock unlocked return false; } + if (isThreadRunning_) { + LOG4CXX_TRACE(logger_, "EXIT thread "<< name_ + << " #" << handle_ << "is already runing"); + return true; + } + thread_options_ = options; pthread_attr_t attributes; int pthread_result = pthread_attr_init(&attributes); if (pthread_result != EOK) { LOG4CXX_WARN(logger_,"Couldn't init pthread attributes. Error code = " - << pthread_result << "(\"" << strerror(pthread_result) << "\")"); + << pthread_result << " (\"" << strerror(pthread_result) << "\")"); } if (!thread_options_.is_joinable()) { pthread_result = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); if (pthread_result != EOK) { - LOG4CXX_WARN(logger_,"Couldn't set detach state attribute.. Error code = " - << pthread_result << "(\"" << strerror(pthread_result) << "\")"); + LOG4CXX_WARN(logger_,"Couldn't set detach state attribute. Error code = " + << pthread_result << " (\"" << strerror(pthread_result) << "\")"); thread_options_.is_joinable(false); } } @@ -159,66 +201,78 @@ bool Thread::startWithOptions(const ThreadOptions& options) { pthread_result = pthread_attr_setstacksize(&attributes, stack_size); if (pthread_result != EOK) { LOG4CXX_WARN(logger_,"Couldn't set stacksize = " << stack_size << - ". Error code = " << pthread_result << "(\"" - << strerror(pthread_result) << "\")"); + ". Error code = " << pthread_result + << " (\"" << strerror(pthread_result) << "\")"); } } - pthread_result = pthread_create(&thread_handle_, &attributes, threadFunc, this); - isThreadRunning_ = (pthread_result == EOK); - if (!isThreadRunning_) { - LOG4CXX_WARN(logger_, "Couldn't create thread. Error code = " - << pthread_result << "(\"" << strerror(pthread_result) << "\")"); - } else { - LOG4CXX_INFO(logger_,"Created thread: " << name_); - SetNameForId(Id(thread_handle_), name_); + if (!thread_created_) { + // state_lock 1 + pthread_result = pthread_create(&handle_, &attributes, threadFunc, this); + if (pthread_result == EOK) { + LOG4CXX_INFO(logger_,"Created thread: " << name_); + SetNameForId(handle_, name_); + // state_lock 0 + // possible concurrencies: stop and threadFunc + state_cond_.Wait(auto_lock); + thread_created_ = true; + } else { + LOG4CXX_ERROR(logger_, "Couldn't create thread " << name_ + << ". Error code = " << pthread_result + << " (\"" << strerror(pthread_result) << "\")"); + } } - LOG4CXX_TRACE_EXIT(logger_); - return isThreadRunning_; + stopped_ = false; + run_cond_.NotifyOne(); + LOG4CXX_DEBUG(logger_,"Thread " << name_ + << " #" << handle_ << " started. pthread_result = " + << pthread_result); + return pthread_result == EOK; } void Thread::stop() { - LOG4CXX_TRACE_ENTER(logger_); + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock auto_lock(state_lock_); - if (!atomic_post_clr(&isThreadRunning_)) - { - return; - } + stopped_ = true; - if (delegate_ && !delegate_->exitThreadMain()) { - if (thread_handle_ != pthread_self()) { - LOG4CXX_WARN(logger_, "Cancelling thread #" << thread_handle_); - const int pthread_result = pthread_cancel(thread_handle_); - if (pthread_result != EOK) { - LOG4CXX_WARN(logger_, - "Couldn't cancel thread (#" << thread_handle_ << " \"" << name_ << - "\") from thread #" << pthread_self() << ". Error code = " - << pthread_result << " (\"" << strerror(pthread_result) << "\")"); - } - } else { - LOG4CXX_ERROR(logger_, - "Couldn't cancel the same thread (#" << thread_handle_ - << "\"" << name_ << "\")"); - } + LOG4CXX_DEBUG(logger_, "Stopping thread #" << handle_ + << " \"" << name_ << " \""); + + if (delegate_ && isThreadRunning_) { + delegate_->exitThreadMain(); } - LOG4CXX_TRACE_EXIT(logger_); + LOG4CXX_DEBUG(logger_, "Stopped thread #" << handle_ + << " \"" << name_ << " \""); } -bool Thread::Id::operator==(const Thread::Id& other) const { - return pthread_equal(id_, other.id_) != 0; -} +void Thread::join() { + LOG4CXX_AUTO_TRACE(logger_); + DCHECK(!pthread_equal(pthread_self(), handle_)); + + stop(); -std::ostream& operator<<(std::ostream& os, const Thread::Id& thread_id) { - char name[32]; - if(pthread_getname_np(thread_id.Handle(), name, 32) == 0) { - os << name; + sync_primitives::AutoLock auto_lock(state_lock_); + run_cond_.NotifyOne(); + if (isThreadRunning_) { + if(!pthread_equal(pthread_self(), handle_)) { + state_cond_.Wait(auto_lock); + } } - return os; +} + +Thread::~Thread() { + finalized_ = true; + stopped_ = true; + join(); + pthread_join(handle_, NULL); } Thread* CreateThread(const char* name, ThreadDelegate* delegate) { - return new Thread(name, delegate); + Thread* thread = new Thread(name, delegate); + delegate->set_thread(thread); + return thread; } void DeleteThread(Thread* thread) { @@ -226,4 +280,5 @@ void DeleteThread(Thread* thread) { } + } // namespace threads diff --git a/src/components/utils/src/threads/pulse_thread_delegate.cc b/src/components/utils/src/threads/pulse_thread_delegate.cc index 8c580bea83..68db5dcbea 100644 --- a/src/components/utils/src/threads/pulse_thread_delegate.cc +++ b/src/components/utils/src/threads/pulse_thread_delegate.cc @@ -91,7 +91,7 @@ void PulseThreadDelegate::threadMain() { Finalize(); } -bool PulseThreadDelegate::exitThreadMain() { +void PulseThreadDelegate::exitThreadMain() { run_ = false; LOG4CXX_TRACE(logger_, "Disconnecting from QNX channel " << chid_); @@ -109,8 +109,6 @@ bool PulseThreadDelegate::exitThreadMain() { else { LOG4CXX_WARN(logger_, "Failed to destroy QNX channel " << chid_); } - - return true; } } // namespace threads diff --git a/src/components/utils/src/threads/thread_delegate.cc b/src/components/utils/src/threads/thread_delegate.cc new file mode 100644 index 0000000000..13271166ff --- /dev/null +++ b/src/components/utils/src/threads/thread_delegate.cc @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#include "utils/threads/thread_delegate.h" + +#include <pthread.h> + +#include "utils/threads/thread.h" +#include "utils/lock.h" + +namespace threads { + +ThreadDelegate::~ThreadDelegate() { + if(thread_) { + thread_->set_delegate(NULL); + } +} + +void ThreadDelegate::exitThreadMain() { + if (thread_) { + if (thread_->thread_handle() == pthread_self()) { + pthread_exit(NULL); + } else { + pthread_cancel(thread_->thread_handle()); + } + } +} + +void ThreadDelegate::set_thread(Thread *thread) { + DCHECK(thread && !thread->is_running()); + thread_ = thread; +} + +} diff --git a/src/components/utils/src/threads/thread_validator.cc b/src/components/utils/src/threads/thread_validator.cc index 5e9c88a7c9..d10a736078 100644 --- a/src/components/utils/src/threads/thread_validator.cc +++ b/src/components/utils/src/threads/thread_validator.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -46,7 +46,7 @@ SingleThreadSimpleValidator::~SingleThreadSimpleValidator() { } void SingleThreadSimpleValidator::AssertRunningOnCreationThread() const { - Thread::Id current_id = Thread::CurrentId(); + PlatformThreadHandle current_id = Thread::CurrentId(); if (creation_thread_id_ != current_id) { LOG4CXX_ERROR(logger_, "Single-threaded object created at thread " << creation_thread_id_ @@ -68,12 +68,12 @@ SingleThreadValidator::SingleThreadValidator() SingleThreadValidator::~SingleThreadValidator() { } -void SingleThreadValidator::PassToThread(Thread::Id thread_id) const { +void SingleThreadValidator::PassToThread(PlatformThreadHandle thread_id) const { owning_thread_id_ = thread_id; } void SingleThreadValidator::AssertRunningOnValidThread() const { - Thread::Id current_id = Thread::CurrentId(); + PlatformThreadHandle current_id = Thread::CurrentId(); if (owning_thread_id_ != current_id) { LOG4CXX_ERROR(logger_, "Single-threaded object owned by thread " << owning_thread_id_ diff --git a/src/components/utils/test/CMakeLists.txt b/src/components/utils/test/CMakeLists.txt index a9ed5acdac..15e086b117 100644 --- a/src/components/utils/test/CMakeLists.txt +++ b/src/components/utils/test/CMakeLists.txt @@ -4,6 +4,7 @@ include_directories ( set(testSources main.cc + messagemeter_test.cc file_system_test.cc date_time_test.cc) diff --git a/src/components/utils/test/date_time_test.cc b/src/components/utils/test/date_time_test.cc index ddcf679a16..e092d16293 100644 --- a/src/components/utils/test/date_time_test.cc +++ b/src/components/utils/test/date_time_test.cc @@ -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. + */ #include <unistd.h> diff --git a/src/components/utils/test/messagemeter_test.cc b/src/components/utils/test/messagemeter_test.cc new file mode 100644 index 0000000000..45375e4ed6 --- /dev/null +++ b/src/components/utils/test/messagemeter_test.cc @@ -0,0 +1,283 @@ +/* +* 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. +*/ + +#include <unistd.h> + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "utils/macro.h" + +#include "utils/messagemeter.h" +#include "utils/date_time.h" + +namespace test { +namespace components { +namespace utils { + +// Pair of values <second, msecond> +typedef std::pair<int, int> TimePair; +const TimePair testing_time_pairs[] = { TimePair(0, 50), + TimePair(0, 100), + TimePair(0, 200), + TimePair(0, 500), + TimePair(0, 900), + TimePair(1, 0), + TimePair(1, 500) }; + +class MessageMeterTest: public ::testing::TestWithParam<TimePair> { + protected: + void SetUp() OVERRIDE { + usecs = date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + id1 = 0x0; + id2 = 0xABCDEF; + id3 = 0xFEBCDA; + + const TimePair time_pair = GetParam(); + EXPECT_GT(usecs, + time_pair.second) << "Wrong time (msecs) value"; + + time_range.tv_sec = time_pair.first; + time_range.tv_usec = time_pair.second * usecs; + EXPECT_LT(0, + date_time::DateTime::getuSecs(time_range)) + << "Wrong test case with null range value"; + + meter.set_time_range(time_range); + // Get range in msec less than original for correct waitng in tests + time_range_msecs = date_time::DateTime::getmSecs(time_range) * 0.95; + } + void TearDown() OVERRIDE { + } + ::utils::MessageMeter<int> meter; + TimevalStruct time_range {0, 0}; + int64_t time_range_msecs; + int usecs; + int id1, id2, id3; +}; + +TEST(MessageMeterTest, DefaultTimeRange) { + const ::utils::MessageMeter<int> default_meter; + const TimevalStruct time_second {1, 0}; + EXPECT_EQ(time_second, default_meter.time_range()); +} + +TEST(MessageMeterTest, TimeRangeSetter) { + ::utils::MessageMeter<int> meter; + TimevalStruct time_range {0, 0}; + const int test_count_secs = 1000; + // Skip 1000th msec value as wrong for TimevalStruct + const int test_count_msecs = 999; + for (int sec = test_count_secs; sec >= 0; --sec) { + for (int msec = test_count_msecs; msec >= 0; --msec) { + time_range.tv_sec = sec; + time_range.tv_usec = msec * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + // Setter TimevalStruct + meter.set_time_range(time_range); + EXPECT_EQ(time_range, + meter.time_range()) << sec << "." << msec << " sec"; + // Setter mSecs + meter.set_time_range(sec * date_time::DateTime::MILLISECONDS_IN_SECOND + + msec); + EXPECT_EQ(time_range, + meter.time_range()) << sec << "." << msec << " sec"; + } + } +} + +TEST(MessageMeterTest, AddingWithNullTimeRange) { + ::utils::MessageMeter<int> meter; + const int id1 = 1; + const int id2 = 2; + const TimevalStruct null_time_range {0, 0}; + meter.set_time_range(null_time_range); + for (int i = 0; i < 10000; ++i) { + // 1st Connection + EXPECT_EQ(0u, + meter.TrackMessage(id1)); + EXPECT_EQ(0u, + meter.Frequency(id1)); + + // 2d Connection + EXPECT_EQ(0u, + meter.TrackMessage(id2)); + EXPECT_EQ(0u, + meter.Frequency(id2)); + } +} + +TEST_P(MessageMeterTest, AddingOverPeriod) { + size_t messages = 0; + const TimevalStruct start_time = date_time::DateTime::getCurrentTime(); + // Add messages for less range period + while (date_time::DateTime::calculateTimeSpan(start_time) + < time_range_msecs) { + ++messages; + EXPECT_EQ(messages, + meter.TrackMessage(id1)); + EXPECT_EQ(messages, + meter.Frequency(id1)); + } +} + +TEST_P(MessageMeterTest, AddingOverPeriod_MultiIds) { + size_t messages = 0; + const TimevalStruct start_time = date_time::DateTime::getCurrentTime(); + // Add messages for less range period + while (date_time::DateTime::calculateTimeSpan(start_time) + < time_range_msecs) { + ++messages; + // 1st Connection + EXPECT_EQ(messages, + meter.TrackMessage(id1)); + EXPECT_EQ(messages, + meter.Frequency(id1)); + + // 2d Connection + EXPECT_EQ(messages, + meter.TrackMessage(id2)); + EXPECT_EQ(messages, + meter.Frequency(id2)); + + // 3d Connection + EXPECT_EQ(messages, + meter.TrackMessage(id3)); + EXPECT_EQ(messages, + meter.Frequency(id3)); + } +} + +TEST_P(MessageMeterTest, CountingOverPeriod) { + const size_t one_message = 1; + const TimevalStruct start_time = date_time::DateTime::getCurrentTime(); + EXPECT_EQ(one_message, + meter.TrackMessage(id1)); + EXPECT_EQ(one_message, + meter.TrackMessage(id2)); + EXPECT_EQ(one_message, + meter.TrackMessage(id3)); + const int sleep_usecs = 500; + // Check messages count over period + while (date_time::DateTime::calculateTimeSpan(start_time) + < time_range_msecs) { + usleep(sleep_usecs); + EXPECT_EQ(one_message, + meter.Frequency(id1)); + EXPECT_EQ(one_message, + meter.Frequency(id2)); + EXPECT_EQ(one_message, + meter.Frequency(id3)); + } +} + +TEST_P(MessageMeterTest, CountingOutOfPeriod) { + const size_t one_message = 1; + EXPECT_EQ(one_message, + meter.TrackMessage(id1)); + EXPECT_EQ(one_message, + meter.TrackMessage(id2)); + EXPECT_EQ(one_message, + meter.TrackMessage(id3)); + + // sleep more than time range + usleep(time_range_msecs * usecs * 1.1); + EXPECT_EQ(0u, + meter.Frequency(id1)); + EXPECT_EQ(0u, + meter.Frequency(id2)); + EXPECT_EQ(0u, + meter.Frequency(id3)); +} + +TEST_P(MessageMeterTest, ClearId) { + const size_t one_message = 1; + EXPECT_EQ(one_message, + meter.TrackMessage(id1)); + EXPECT_EQ(one_message, + meter.TrackMessage(id2)); + EXPECT_EQ(one_message, + meter.TrackMessage(id3)); + + meter.RemoveIdentifier(id1); + + EXPECT_EQ(0u, + meter.Frequency(id1)); + EXPECT_EQ(one_message, + meter.Frequency(id2)); + EXPECT_EQ(one_message, + meter.Frequency(id3)); + + meter.RemoveIdentifier(id2); + + EXPECT_EQ(0u, + meter.Frequency(id1)); + EXPECT_EQ(0u, + meter.Frequency(id2)); + EXPECT_EQ(one_message, + meter.Frequency(id3)); + + meter.RemoveIdentifier(id3); + + EXPECT_EQ(0u, + meter.Frequency(id1)); + EXPECT_EQ(0u, + meter.Frequency(id2)); + EXPECT_EQ(0u, + meter.Frequency(id3)); +} + +TEST_P(MessageMeterTest, ClearIds) { + const size_t one_message = 1; + EXPECT_EQ(one_message, + meter.TrackMessage(id1)); + EXPECT_EQ(one_message, + meter.TrackMessage(id2)); + EXPECT_EQ(one_message, + meter.TrackMessage(id3)); + + meter.ClearIdentifiers(); + + EXPECT_EQ(0u, + meter.Frequency(id2)); + EXPECT_EQ(0u, + meter.Frequency(id2)); + EXPECT_EQ(0u, + meter.Frequency(id3)); +} + +INSTANTIATE_TEST_CASE_P(MessageMeterTestCase, + MessageMeterTest, + ::testing::ValuesIn(testing_time_pairs)); + +} // namespace utils +} // namespace components +} // namespace test |