diff options
Diffstat (limited to 'src/components/utils/src')
-rw-r--r-- | src/components/utils/src/appenders_loader.cc | 2 | ||||
-rw-r--r-- | src/components/utils/src/back_trace.cc | 4 | ||||
-rw-r--r-- | src/components/utils/src/bitstream.cc | 2 | ||||
-rw-r--r-- | src/components/utils/src/conditional_variable_posix.cc | 23 | ||||
-rw-r--r-- | src/components/utils/src/date_time.cc | 81 | ||||
-rw-r--r-- | src/components/utils/src/file_system.cc | 17 | ||||
-rw-r--r-- | src/components/utils/src/gen_hash.cc | 53 | ||||
-rw-r--r-- | src/components/utils/src/lock_posix.cc | 57 | ||||
-rw-r--r-- | src/components/utils/src/logger_status.cc | 2 | ||||
-rw-r--r-- | src/components/utils/src/resource_usage.cc | 6 | ||||
-rw-r--r-- | src/components/utils/src/rwlock_posix.cc | 30 | ||||
-rw-r--r-- | src/components/utils/src/signals_linux.cc | 83 | ||||
-rw-r--r-- | src/components/utils/src/system.cc | 21 | ||||
-rw-r--r-- | src/components/utils/src/threads/posix_thread.cc | 299 | ||||
-rw-r--r-- | src/components/utils/src/threads/pulse_thread_delegate.cc | 4 | ||||
-rw-r--r-- | src/components/utils/src/threads/thread_delegate.cc | 6 | ||||
-rw-r--r-- | src/components/utils/src/threads/thread_validator.cc | 15 |
17 files changed, 446 insertions, 259 deletions
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/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..2928cac9db 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,14 +83,29 @@ void ConditionalVariable::Broadcast() { } -void ConditionalVariable::Wait(AutoLock& auto_lock) { +bool 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"); + return false; + } + return true; +} + +bool ConditionalVariable::Wait(AutoLock& auto_lock) { Lock& lock = auto_lock.GetLock(); lock.AssertTakenAndMarkFree(); int32_t wait_status = pthread_cond_wait(&cond_var_, &lock.mutex_); lock.AssertFreeAndMarkTaken(); - if (wait_status != 0) + if (wait_status != 0) { LOG4CXX_ERROR(logger_, "Failed to wait for conditional variable"); + return false; + } + return true; } ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( @@ -104,7 +119,6 @@ ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( (milliseconds % kMillisecondsPerSecond) * kNanosecondsPerMillisecond; wait_interval.tv_sec += wait_interval.tv_nsec / kNanosecondsPerSecond; wait_interval.tv_nsec %= kNanosecondsPerSecond; - Lock& lock = auto_lock.GetLock(); lock.AssertTakenAndMarkFree(); int32_t timedwait_status = pthread_cond_timedwait(&cond_var_, @@ -129,7 +143,6 @@ ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( LOG4CXX_ERROR(logger_, "Failed to timewait for conditional variable timedwait_status: " << timedwait_status); } } - return wait_status; } diff --git a/src/components/utils/src/date_time.cc b/src/components/utils/src/date_time.cc index f190951647..42a199e0fb 100644 --- a/src/components/utils/src/date_time.cc +++ b/src/components/utils/src/date_time.cc @@ -1,49 +1,50 @@ /* -* 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> #include "utils/date_time.h" + namespace date_time { -TimevalStruct DateTime::getCurrentTime() { - TimevalStruct currentTime; - timezone timeZone; + TimevalStruct DateTime::getCurrentTime() { + TimevalStruct currentTime; + timezone timeZone; - gettimeofday(¤tTime, &timeZone); + gettimeofday(¤tTime, &timeZone); - return currentTime; -} + return currentTime; + } int64_t date_time::DateTime::getSecs(const TimevalStruct &time) { return static_cast<int64_t>(time.tv_sec); @@ -100,3 +101,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..69efcad863 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; } @@ -410,3 +412,14 @@ bool file_system::CreateFile(const std::string& path) { return true; } } + + +uint64_t file_system::GetFileModificationTime(const std::string& path) { + struct stat info; + stat(path.c_str(), &info); +#ifndef __QNXNTO__ + return static_cast<uint64_t>(info.st_mtim.tv_nsec); +#else + return static_cast<uint64_t>(info.st_mtime); +#endif +} diff --git a/src/components/utils/src/gen_hash.cc b/src/components/utils/src/gen_hash.cc new file mode 100644 index 0000000000..6ac5c217c3 --- /dev/null +++ b/src/components/utils/src/gen_hash.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/gen_hash.h" + +#include <cstdlib> + +namespace utils { + +const std::string gen_hash(size_t size) { + static const char symbols[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static const size_t capacity = sizeof(symbols) - 1; + + std::string hash(size, '\0'); + for (std::string::iterator i = hash.begin(); i != hash.end(); ++i) { + int index = std::rand() % capacity; + *i = symbols[index]; + } + return hash; +} + +} // namespace utils diff --git a/src/components/utils/src/lock_posix.cc b/src/components/utils/src/lock_posix.cc index f75b7ee9ea..d2837708fa 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" @@ -43,11 +45,11 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") Lock::Lock() #ifndef NDEBUG - : lock_taken_(0), - is_mutex_recursive_(false) + : lock_taken_(0), + 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"); } @@ -55,8 +57,8 @@ Lock::Lock() Lock::Lock(bool is_mutex_recursive) #ifndef NDEBUG - : lock_taken_(0), - is_mutex_recursive_(is_mutex_recursive) + : lock_taken_(0), + is_mutex_recursive_(is_mutex_recursive) #endif // NDEBUG { int32_t status; @@ -67,6 +69,7 @@ Lock::Lock(bool is_mutex_recursive) pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); status = pthread_mutex_init(&mutex_, &attr); + pthread_mutexattr_destroy(&attr); } else { status = pthread_mutex_init(&mutex_, NULL); } @@ -79,54 +82,41 @@ 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_); + const 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_); + const int32_t status = pthread_mutex_unlock(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to unlock mutex"); + LOG4CXX_ERROR(logger_, "Failed to unlock mutex" << &mutex_ << ": " << strerror(status)); } } 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; + const int32_t status = pthread_mutex_trylock(&mutex_); + if (status == 0) { #ifndef NDEBUG - lock_taken_++; + lock_taken_++; #endif - } break; - case EBUSY: { - ackquired = false; - } break; - default: { - ackquired = false; - LOG4CXX_ERROR(logger_, "Failed to try lock the mutex"); - } + return true; } - return ackquired; + return false; } #ifndef NDEBUG @@ -146,5 +136,4 @@ void Lock::AssertTakenAndMarkFree() { } #endif - -} // namespace sync_primitives +} // namespace sync_primitives 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/rwlock_posix.cc b/src/components/utils/src/rwlock_posix.cc index 7cc850b25b..08edb8cb0c 100644 --- a/src/components/utils/src/rwlock_posix.cc +++ b/src/components/utils/src/rwlock_posix.cc @@ -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 @@ -49,22 +49,44 @@ RWLock::~RWLock() { } } -void RWLock::AcquireForReading() { +bool RWLock::AcquireForReading() { if (pthread_rwlock_rdlock(&rwlock_) != 0) { LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for reading"); + return false; } + return true; } -void RWLock::AcquireForWriting() { +bool RWLock::TryAcquireForReading() { + if (pthread_rwlock_tryrdlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for reading"); + return false; + } + return true; +} + +bool RWLock::AcquireForWriting() { if (pthread_rwlock_wrlock(&rwlock_) != 0) { LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for writing"); + return false; + } + return true; +} + +bool RWLock::TryAcquireForWriting() { + if (pthread_rwlock_trywrlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for writing"); + return false; } + return true; } -void RWLock::Release() { +bool RWLock::Release() { if (pthread_rwlock_unlock(&rwlock_) != 0) { LOG4CXX_ERROR(logger_, "Failed to release rwlock"); + return false; } + return true; } } // namespace sync_primitives 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..70659419a7 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. * @@ -42,6 +42,7 @@ #include <algorithm> #include <functional> #include <cstring> +#include <iostream> #include "utils/logger.h" #include "utils/system.h" @@ -66,15 +67,23 @@ System::System(const std::string& file, const std::string& command) argv_.push_back(command); } -bool System::Execute() { - return Execute(false); -} - System& System::Add(const std::string& arg) { argv_.push_back(arg); return *this; } +std::string System::command() const { + return command_; +} + +std::vector<std::string> System::argv() const { + return argv_; +} + +bool System::Execute() { + return Execute(false); +} + #ifdef __QNX__ bool System::Execute(bool wait) { @@ -89,7 +98,7 @@ bool System::Execute(bool wait) { if (ret == -1) { LOG4CXX_ERROR(logger_, "Can't execute command: " << command_ - << " Errno is: " << std::strerror(errno)); + << " Errno is: " << std::strerror(errno)); return false; } diff --git a/src/components/utils/src/threads/posix_thread.cc b/src/components/utils/src/threads/posix_thread.cc index 3f7e006eca..82dd8c59b3 100644 --- a/src/components/utils/src/threads/posix_thread.cc +++ b/src/components/utils/src/threads/posix_thread.cc @@ -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 @@ -31,125 +31,168 @@ */ #include <errno.h> - #include <limits.h> #include <stddef.h> #include <signal.h> -#include "utils/atomic.h" +#ifdef BUILD_TESTS +// Temporary fix for UnitTest until APPLINK-9987 is resolved +#include <unistd.h> +#endif + #include "utils/threads/thread.h" -#include "utils/threads/thread_manager.h" -#include "utils/logger.h" #include "pthread.h" - +#include "utils/atomic.h" +#include "utils/threads/thread_delegate.h" +#include "utils/logger.h" #ifndef __QNXNTO__ - const int EOK = 0; +const int EOK = 0; #endif #if defined(OS_POSIX) - const size_t THREAD_NAME_SIZE = 15; +const size_t THREAD_NAME_SIZE = 15; #endif 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* 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"); + } -/* -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) - << ")"); - } + 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) { - LOG4CXX_WARN(logger_, "Couldn't set pthread name \"" - << trimname - << "\", error code " - << rc - << " (" - << strerror(rc) - << ")"); + +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 \"" << name << "\", error code " << rc << " (" << strerror(rc) << ")"); } } Thread::Thread(const char* name, ThreadDelegate* delegate) - : name_(name ? name : "undefined"), - delegate_(delegate), - thread_handle_(0), - thread_options_(), - isThreadRunning_(0) { -} - -ThreadDelegate* Thread::delegate() const { - return delegate_; + : name_(name ? name : "undefined"), + delegate_(delegate), + handle_(0), + thread_options_(), + isThreadRunning_(0), + stopped_(false), + finalized_(false), + thread_created_(false) { } bool Thread::start() { - return startWithOptions(thread_options_); + return start(thread_options_); } -Thread::Id Thread::CurrentId() { - return Id(pthread_self()); +PlatformThreadHandle Thread::CurrentId() { + return pthread_self(); } -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 running"); + 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) << "\")"); + LOG4CXX_WARN( + logger_, + "Couldn't init pthread attributes. Error code = " << 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); } } @@ -158,72 +201,94 @@ bool Thread::startWithOptions(const ThreadOptions& options) { if (stack_size >= Thread::kMinStackSize) { 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) << "\")"); + LOG4CXX_WARN( + logger_, + "Couldn't set stacksize = " << stack_size << ". Error code = " << pthread_result << " (\"" << strerror(pthread_result) << "\")"); } } + else { + ThreadOptions thread_options_temp(Thread::kMinStackSize, thread_options_.is_joinable()); + thread_options_ = thread_options_temp; + } - 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_DEBUG(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); + pthread_attr_destroy(&attributes); + 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; - } +#ifdef BUILD_TESTS + // Temporary fix for UnitTest until APPLINK-9987 is resolved + usleep(100000); +#endif - 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_ << "\")"); - } + stopped_ = true; + + 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_)); -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; + stop(); + + 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) { delete 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 index 13271166ff..1436ea3377 100644 --- a/src/components/utils/src/threads/thread_delegate.cc +++ b/src/components/utils/src/threads/thread_delegate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,7 @@ namespace threads { ThreadDelegate::~ThreadDelegate() { - if(thread_) { + if (thread_) { thread_->set_delegate(NULL); } } @@ -60,4 +60,4 @@ void ThreadDelegate::set_thread(Thread *thread) { thread_ = thread; } -} +} // namespace threads diff --git a/src/components/utils/src/threads/thread_validator.cc b/src/components/utils/src/threads/thread_validator.cc index 5e9c88a7c9..99b812c456 100644 --- a/src/components/utils/src/threads/thread_validator.cc +++ b/src/components/utils/src/threads/thread_validator.cc @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2013, Ford Motor Company +/* + * Copyright (c) 2014, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -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_ @@ -60,6 +60,11 @@ void SingleThreadSimpleValidator::AssertRunningOnCreationThread() const { } } +PlatformThreadHandle SingleThreadSimpleValidator::creation_thread_id() const +{ + return creation_thread_id_; +} + SingleThreadValidator::SingleThreadValidator() : owning_thread_id_(Thread::CurrentId()){ @@ -68,12 +73,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_ |