diff options
Diffstat (limited to 'src/components/utils/src')
-rw-r--r-- | src/components/utils/src/conditional_variable_boost.cc | 135 | ||||
-rw-r--r-- | src/components/utils/src/conditional_variable_posix.cc | 149 | ||||
-rw-r--r-- | src/components/utils/src/date_time.cc | 123 | ||||
-rw-r--r-- | src/components/utils/src/file_system.cc | 317 | ||||
-rw-r--r-- | src/components/utils/src/lock_boost.cc (renamed from src/components/utils/src/lock_posix.cc) | 115 | ||||
-rw-r--r-- | src/components/utils/src/log_message_loop_thread.cc | 7 | ||||
-rw-r--r-- | src/components/utils/src/logger.cc | 3 | ||||
-rw-r--r-- | src/components/utils/src/semantic_version.cc | 39 | ||||
-rw-r--r-- | src/components/utils/src/signals_posix.cc | 44 | ||||
-rw-r--r-- | src/components/utils/src/system_time_handler.cc | 62 |
10 files changed, 511 insertions, 483 deletions
diff --git a/src/components/utils/src/conditional_variable_boost.cc b/src/components/utils/src/conditional_variable_boost.cc new file mode 100644 index 0000000000..a74aa3eaa6 --- /dev/null +++ b/src/components/utils/src/conditional_variable_boost.cc @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 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/conditional_variable.h" + +#include <errno.h> +#include <time.h> + +#include "utils/lock.h" +#include "utils/logger.h" +#include <boost/exception/diagnostic_information.hpp> + +namespace { +const long kNanosecondsPerSecond = 1000000000; +const long kMillisecondsPerSecond = 1000; +const long kNanosecondsPerMillisecond = 1000000; +} // namespace + +namespace sync_primitives { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +ConditionalVariable::ConditionalVariable() {} + +ConditionalVariable::~ConditionalVariable() {} + +void ConditionalVariable::NotifyOne() { + cond_var_.notify_one(); +} + +void ConditionalVariable::Broadcast() { + cond_var_.notify_all(); +} + +bool ConditionalVariable::Wait(BaseLock& lock) { + // NOTE this grossness is due to boost mutex and recursive mutex not sharing a + // superclass + try { + lock.AssertTakenAndMarkFree(); + // What kind of lock are we ? + if (Lock* test_lock = dynamic_cast<Lock*>(&lock)) { + // Regular lock + cond_var_.wait<boost::mutex>(test_lock->mutex_); + } else if (RecursiveLock* test_rec_lock = + dynamic_cast<RecursiveLock*>(&lock)) { + // Recursive lock + cond_var_.wait<boost::recursive_mutex>(test_rec_lock->mutex_); + } else { + // unknown, give up the lock + LOG4CXX_ERROR(logger_, "Unknown lock type!"); + NOTREACHED(); + } + lock.AssertFreeAndMarkTaken(); + } catch (const boost::exception& error) { + std::string error_string = boost::diagnostic_information(error); + LOG4CXX_FATAL(logger_, error_string); + NOTREACHED(); + } + return true; +} + +bool ConditionalVariable::Wait(AutoLock& auto_lock) { + BaseLock& lock = auto_lock.GetLock(); + return Wait(lock); +} + +ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( + AutoLock& auto_lock, uint32_t milliseconds) { + BaseLock& lock = auto_lock.GetLock(); + + WaitStatus wait_status = kNoTimeout; + try { + lock.AssertTakenAndMarkFree(); + bool timeout = true; + + // What kind of lock are we ? + if (Lock* test_lock = dynamic_cast<Lock*>(&lock)) { + // Regular lock + // cond_var_.wait<boost::mutex>(test_lock->mutex_); + timeout = cond_var_.timed_wait<boost::mutex>( + test_lock->mutex_, boost::posix_time::milliseconds(milliseconds)); + } else if (RecursiveLock* test_rec_lock = + dynamic_cast<RecursiveLock*>(&lock)) { + // Recursive lock + // cond_var_.wait<boost::recursive_mutex>(test_rec_lock->mutex_); + timeout = cond_var_.timed_wait<boost::recursive_mutex>( + test_rec_lock->mutex_, boost::posix_time::milliseconds(milliseconds)); + } else { + // this is an unknown lock, we have an issue + LOG4CXX_ERROR(logger_, "Unknown lock type!"); + NOTREACHED(); + } + + if (!timeout) { + wait_status = kTimeout; + } + lock.AssertFreeAndMarkTaken(); + } catch (const boost::exception& error) { + std::string error_string = boost::diagnostic_information(error); + LOG4CXX_FATAL(logger_, error_string); + NOTREACHED(); + } + + return wait_status; +} + +} // namespace sync_primitives diff --git a/src/components/utils/src/conditional_variable_posix.cc b/src/components/utils/src/conditional_variable_posix.cc deleted file mode 100644 index 50ebc74556..0000000000 --- a/src/components/utils/src/conditional_variable_posix.cc +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2013, 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/conditional_variable.h" - -#include <errno.h> -#include <time.h> - -#include "utils/lock.h" -#include "utils/logger.h" - -namespace { -const long kNanosecondsPerSecond = 1000000000; -const long kMillisecondsPerSecond = 1000; -const long kNanosecondsPerMillisecond = 1000000; -} - -namespace sync_primitives { - -CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") - -ConditionalVariable::ConditionalVariable() { - pthread_condattr_t attrs; - int initialized = pthread_condattr_init(&attrs); - if (initialized != 0) - LOG4CXX_ERROR(logger_, - "Failed to initialize " - "conditional variable attributes"); - pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); - initialized = pthread_cond_init(&cond_var_, &attrs); - if (initialized != 0) - LOG4CXX_ERROR(logger_, - "Failed to initialize " - "conditional variable"); - int rv = pthread_condattr_destroy(&attrs); - if (rv != 0) - LOG4CXX_ERROR(logger_, - "Failed to destroy " - "conditional variable attributes"); -} - -ConditionalVariable::~ConditionalVariable() { - pthread_cond_destroy(&cond_var_); -} - -void ConditionalVariable::NotifyOne() { - int signaled = pthread_cond_signal(&cond_var_); - if (signaled != 0) - LOG4CXX_ERROR(logger_, "Failed to signal conditional variable"); -} - -void ConditionalVariable::Broadcast() { - int signaled = pthread_cond_broadcast(&cond_var_); - if (signaled != 0) - LOG4CXX_ERROR(logger_, "Failed to broadcast conditional variable"); -} - -bool ConditionalVariable::Wait(Lock& lock) { - lock.AssertTakenAndMarkFree(); - int 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(); - int 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; -} - -ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( - AutoLock& auto_lock, uint32_t milliseconds) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - timespec wait_interval; - wait_interval.tv_sec = now.tv_sec + (milliseconds / kMillisecondsPerSecond); - wait_interval.tv_nsec = - now.tv_nsec + - (milliseconds % kMillisecondsPerSecond) * kNanosecondsPerMillisecond; - wait_interval.tv_sec += wait_interval.tv_nsec / kNanosecondsPerSecond; - wait_interval.tv_nsec %= kNanosecondsPerSecond; - Lock& lock = auto_lock.GetLock(); - lock.AssertTakenAndMarkFree(); - int timedwait_status = - pthread_cond_timedwait(&cond_var_, &lock.mutex_, &wait_interval); - lock.AssertFreeAndMarkTaken(); - WaitStatus wait_status = kNoTimeout; - switch (timedwait_status) { - case 0: { - wait_status = kNoTimeout; - break; - } - case EINTR: { - wait_status = kNoTimeout; - break; - } - case ETIMEDOUT: { - wait_status = kTimeout; - break; - } - default: { - LOG4CXX_ERROR( - logger_, - "Failed to timewait for conditional variable timedwait_status: " - << timedwait_status); - } - } - return wait_status; -} - -} // namespace sync_primitives diff --git a/src/components/utils/src/date_time.cc b/src/components/utils/src/date_time.cc index fdf0926eb2..3ca6050b3f 100644 --- a/src/components/utils/src/date_time.cc +++ b/src/components/utils/src/date_time.cc @@ -30,94 +30,71 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/time.h> -#include <stdint.h> #include "utils/date_time.h" -namespace date_time { +#include <stdint.h> +#include <sys/time.h> +#include "boost/date_time/posix_time/posix_time.hpp" -TimevalStruct DateTime::getCurrentTime() { - TimevalStruct currentTime; - timezone timeZone; +namespace bpt = boost::posix_time; +using namespace boost::date_time; +namespace date_time { - gettimeofday(¤tTime, &timeZone); +/* Set of helper functions for the TimeDuration struct + */ - return currentTime; +TimeDuration getCurrentTime() { + return bpt::microsec_clock::local_time() - bpt::from_time_t(0); +} +TimeDuration TimeDurationZero() { + return TimeDuration(0, 0, 0, 0); +} +int64_t getSecs(const TimeDuration& t) { + return t.total_seconds(); } -int64_t date_time::DateTime::getSecs(const TimevalStruct& time) { - const TimevalStruct times = ConvertionUsecs(time); - return static_cast<int64_t>(times.tv_sec); +int64_t getmSecs(const TimeDuration& t) { + return t.total_milliseconds(); } -int64_t DateTime::getmSecs(const TimevalStruct& time) { - const TimevalStruct times = ConvertionUsecs(time); - return static_cast<int64_t>(times.tv_sec) * MILLISECONDS_IN_SECOND + - times.tv_usec / MICROSECONDS_IN_MILLISECOND; +int64_t getuSecs(const TimeDuration& t) { + return t.total_microseconds(); } -int64_t DateTime::getuSecs(const TimevalStruct& time) { - const TimevalStruct times = ConvertionUsecs(time); - return static_cast<int64_t>(times.tv_sec) * MILLISECONDS_IN_SECOND * - MICROSECONDS_IN_MILLISECOND + - times.tv_usec; +int64_t get_just_mSecs(const TimeDuration& t) { + return t.total_milliseconds() % MILLISECONDS_IN_SECOND; } -int64_t DateTime::calculateTimeSpan(const TimevalStruct& sinceTime) { - return calculateTimeDiff(getCurrentTime(), sinceTime); +int64_t get_just_uSecs(const TimeDuration& t) { + return t.total_microseconds() % MICROSECONDS_IN_SECOND; } -int64_t DateTime::calculateTimeDiff(const TimevalStruct& time1, - const TimevalStruct& time2) { - const TimevalStruct times1 = ConvertionUsecs(time1); - const TimevalStruct times2 = ConvertionUsecs(time2); - TimevalStruct ret; - if (Greater(times1, times2)) { - ret = Sub(times1, times2); - } else { - ret = Sub(times2, times1); - } - return getmSecs(ret); +int64_t calculateTimeSpan(const TimeDuration& sinceTime) { + return calculateTimeDiff(getCurrentTime(), sinceTime); } -void DateTime::AddMilliseconds(TimevalStruct& time, uint32_t milliseconds) { - const uint32_t sec = milliseconds / MILLISECONDS_IN_SECOND; - const uint32_t usec = - (milliseconds % MILLISECONDS_IN_SECOND) * MICROSECONDS_IN_MILLISECOND; - time.tv_sec += sec; - time.tv_usec += usec; - time = ConvertionUsecs(time); +int64_t calculateTimeDiff(const TimeDuration& time1, + const TimeDuration& time2) { + return std::abs((time1 + -time2).total_milliseconds()); } -TimevalStruct DateTime::Sub(const TimevalStruct& time1, - const TimevalStruct& time2) { - const TimevalStruct times1 = ConvertionUsecs(time1); - const TimevalStruct times2 = ConvertionUsecs(time2); - TimevalStruct ret; - timersub(×1, ×2, &ret); - return ret; +void AddMilliseconds(TimeDuration& t, uint32_t milliseconds) { + t += bpt::milliseconds(milliseconds); } -bool DateTime::Greater(const TimevalStruct& time1, const TimevalStruct& time2) { - const TimevalStruct times1 = ConvertionUsecs(time1); - const TimevalStruct times2 = ConvertionUsecs(time2); - return timercmp(×1, ×2, > ); +bool Greater(const TimeDuration& time1, const TimeDuration& time2) { + return time1 > time2; } -bool DateTime::Less(const TimevalStruct& time1, const TimevalStruct& time2) { - const TimevalStruct times1 = ConvertionUsecs(time1); - const TimevalStruct times2 = ConvertionUsecs(time2); - return timercmp(×1, ×2, < ); +bool Less(const TimeDuration& time1, const TimeDuration& time2) { + return time1 < time2; } -bool DateTime::Equal(const TimevalStruct& time1, const TimevalStruct& time2) { - const TimevalStruct times1 = ConvertionUsecs(time1); - const TimevalStruct times2 = ConvertionUsecs(time2); - return !timercmp(×1, ×2, != ); +bool Equal(const TimeDuration& time1, const TimeDuration& time2) { + return time1 == time2; } -TimeCompare date_time::DateTime::compareTime(const TimevalStruct& time1, - const TimevalStruct& time2) { +TimeCompare compareTime(const TimeDuration& time1, const TimeDuration& time2) { if (Greater(time1, time2)) return GREATER; if (Less(time1, time2)) @@ -125,28 +102,4 @@ TimeCompare date_time::DateTime::compareTime(const TimevalStruct& time1, return EQUAL; } -TimevalStruct date_time::DateTime::ConvertionUsecs(const TimevalStruct& time) { - if (time.tv_usec >= MICROSECONDS_IN_SECOND) { - TimevalStruct time1; - time1.tv_sec = static_cast<int64_t>(time.tv_sec) + - (time.tv_usec / MICROSECONDS_IN_SECOND); - time1.tv_usec = static_cast<int64_t>(time.tv_usec) % MICROSECONDS_IN_SECOND; - return time1; - } - return time; -} - } // 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); -} - -const TimevalStruct operator-(const TimevalStruct& time1, - const TimevalStruct& time2) { - return date_time::DateTime::Sub(time1, time2); -} diff --git a/src/components/utils/src/file_system.cc b/src/components/utils/src/file_system.cc index 62a91ad1f3..f98aeda056 100644 --- a/src/components/utils/src/file_system.cc +++ b/src/components/utils/src/file_system.cc @@ -33,125 +33,114 @@ #include "utils/file_system.h" #include "utils/logger.h" -#include <sys/statvfs.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <sys/types.h> #include <sstream> #include <dirent.h> #include <unistd.h> // TODO(VS): lint error: Streams are highly discouraged. -#include <fstream> +#include <algorithm> +#include <boost/filesystem.hpp> #include <cstddef> #include <cstdio> -#include <algorithm> +#include <fstream> CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") +// Easier reference +namespace fs = boost::filesystem; +using boost::system::error_code; + uint64_t file_system::GetAvailableDiskSpace(const std::string& path) { - struct statvfs fsInfo = {0}; - if (statvfs(path.c_str(), &fsInfo) == 0) { - return fsInfo.f_bsize * fsInfo.f_bfree; - } else { + error_code ec; + fs::space_info si = fs::space(path, ec); + + if (ec) { + // If something went wrong, assume no free space return 0; + } else { + return si.free; } } -int64_t file_system::FileSize(const std::string& path) { - if (file_system::FileExists(path)) { - struct stat file_info = {0}; - if (0 != stat(path.c_str(), &file_info)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Could not get file size: " << path); - } else { - return file_info.st_size; - } +uint64_t file_system::FileSize(const std::string& path) { + error_code ec; + // Boost returns sizes as unsigned + uint64_t fsize = (uint64_t)fs::file_size(path, ec); + + if (ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, "Could not get file size: " << path); + return 0; } - return 0; + return fsize; } size_t file_system::DirectorySize(const std::string& path) { - size_t size = 0; - int32_t return_code = 0; - DIR* directory = NULL; - struct dirent dir_element_; - struct dirent* dir_element = &dir_element_; - struct dirent* result = NULL; - struct stat file_info = {0}; - directory = opendir(path.c_str()); - if (NULL != directory) { - return_code = readdir_r(directory, dir_element, &result); - for (; NULL != result && 0 == return_code; - return_code = readdir_r(directory, dir_element, &result)) { - if (0 == strcmp(result->d_name, "..") || - 0 == strcmp(result->d_name, ".")) { - continue; - } - std::string full_element_path = path + "/" + result->d_name; - if (file_system::IsDirectory(full_element_path)) { - size += DirectorySize(full_element_path); - } else { - stat(full_element_path.c_str(), &file_info); - size += file_info.st_size; - } + size_t dir_size = 0; + error_code ec; + // Recursively iterate through directory to accumulate file sizes + fs::recursive_directory_iterator iter(path, ec); + // Directory does not exist + if (ec) { + return 0; + } + // default constructor gives end iterator + fs::recursive_directory_iterator end; + while (iter != end) { + size_t fsize = fs::file_size(iter->path(), ec); + // No error means we can add the file + if (!ec) { + dir_size += fsize; } + iter++; // next entry } - closedir(directory); - return size; + return dir_size; } +// NOTE that boost makes 0777 permissions by default std::string file_system::CreateDirectory(const std::string& name) { - if (!DirectoryExists(name)) { - if (0 != mkdir(name.c_str(), S_IRWXU)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Unable to create directory: " << name); - } + error_code ec; + bool success = fs::create_directory(name, ec); + if (!success || ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, "Unable to create directory: " << name); + } else { + // Set 0700 permissions to maintain previous API + fs::permissions(name, fs::perms::owner_all, ec); } - return name; } bool file_system::CreateDirectoryRecursively(const std::string& path) { - size_t pos = 0; - bool ret_val = true; - - while (ret_val == true && pos <= path.length()) { - pos = path.find('/', pos + 1); - if (!DirectoryExists(path.substr(0, pos))) { - if (0 != mkdir(path.substr(0, pos).c_str(), S_IRWXU)) { - ret_val = false; - } - } - } + error_code ec; + // Create directory and all parents + fs::create_directories(path, ec); - return ret_val; -} + if (ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, + "Unable to create directory recursively: " + << path << " reason: " << ec.message()); -bool file_system::IsDirectory(const std::string& name) { - struct stat status = {0}; - - if (-1 == stat(name.c_str(), &status)) { return false; } - - return S_ISDIR(status.st_mode); + // return true if we made something or if it already existed + return true; } +bool file_system::IsDirectory(const std::string& name) { + error_code ec; + return fs::is_directory(name, ec); +} +// NOTE this may be a duplicate of IsDirectory since it already checks +// existence bool file_system::DirectoryExists(const std::string& name) { - struct stat status = {0}; - - if (-1 == stat(name.c_str(), &status) || !S_ISDIR(status.st_mode)) { - return false; - } - - return true; + return FileExists(name) && IsDirectory(name); } bool file_system::FileExists(const std::string& name) { - struct stat status = {0}; - - if (-1 == stat(name.c_str(), &status)) { - return false; - } - return true; + error_code ec; + return fs::exists(name, ec); } bool file_system::Write(const std::string& file_name, @@ -200,80 +189,75 @@ void file_system::Close(std::ofstream* file_stream) { } std::string file_system::CurrentWorkingDirectory() { - const size_t filename_max_length = 1024; - char path[filename_max_length]; - if (0 == getcwd(path, filename_max_length)) { + error_code ec; + fs::path currpath = fs::current_path(ec); + if (ec) { LOG4CXX_WARN(logger_, "Could not get CWD"); } - return std::string(path); + return currpath.string(); } std::string file_system::GetAbsolutePath(const std::string& path) { - char abs_path[PATH_MAX]; - if (NULL == realpath(path.c_str(), abs_path)) { - return std::string(); + error_code ec; + fs::path absolute = fs::canonical(path, ec); + if (ec) { + return std::string(); // invalid path } - - return std::string(abs_path); + return absolute.string(); } bool file_system::IsFileNameValid(const std::string& file_name) { return file_name.end() == std::find(file_name.begin(), file_name.end(), '/'); } +// Does not remove if file is write-protected bool file_system::DeleteFile(const std::string& name) { if (FileExists(name) && IsAccessible(name, W_OK)) { - return !remove(name.c_str()); + error_code ec; + bool success = fs::remove(name.c_str(), ec); + return success && !ec; } return false; } void file_system::remove_directory_content(const std::string& directory_name) { - int32_t return_code = 0; - DIR* directory = NULL; - struct dirent dir_element_; - struct dirent* dir_element = &dir_element_; - struct dirent* result = NULL; - - directory = opendir(directory_name.c_str()); - - if (NULL != directory) { - return_code = readdir_r(directory, dir_element, &result); - - for (; NULL != result && 0 == return_code; - return_code = readdir_r(directory, dir_element, &result)) { - if (0 == strcmp(result->d_name, "..") || - 0 == strcmp(result->d_name, ".")) { - continue; - } - - std::string full_element_path = directory_name + "/" + result->d_name; - - if (file_system::IsDirectory(full_element_path)) { - remove_directory_content(full_element_path); - rmdir(full_element_path.c_str()); - } else { - if (0 != remove(full_element_path.c_str())) { - LOG4CXX_WARN_WITH_ERRNO( - logger_, "Unable to remove file: " << full_element_path); - } - } - } + error_code ec; + fs::directory_iterator dir_iter(directory_name, ec); + + if (ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, + "Unable to empty directory: " << directory_name); } - closedir(directory); + // According to Boost's documentation, removing shouldn't invalidate the + // iterator, although it may cause the removed entry to appear again, + // duplicating the warning message. See here: + // https://www.boost.org/doc/libs/1_67_0/libs/filesystem/doc/reference.html#Class-directory_iterator + for (auto& dirent : dir_iter) { + fs::remove_all(dirent, ec); + if (ec) { + LOG4CXX_WARN_WITH_ERRNO( + logger_, "Unable to remove file: " << dirent.path().string()); + } + } } bool file_system::RemoveDirectory(const std::string& directory_name, bool is_recursively) { - if (DirectoryExists(directory_name) && IsAccessible(directory_name, W_OK)) { - if (is_recursively) { - remove_directory_content(directory_name); - } - - return !rmdir(directory_name.c_str()); + // Make sure the directory exists + if (!DirectoryExists(directory_name) && IsAccessible(directory_name, W_OK)) { + return false; } - return false; + error_code ec; + bool success; + // If recursive, just force full remove + if (is_recursively) { + success = (fs::remove_all(directory_name, ec) != 0); + } else { + // Otherwise try to remove + success = fs::remove(directory_name, ec); + } + return success && !ec; } bool file_system::IsAccessible(const std::string& name, int32_t how) { @@ -290,34 +274,20 @@ bool file_system::IsReadingAllowed(const std::string& name) { std::vector<std::string> file_system::ListFiles( const std::string& directory_name) { + error_code ec; + + fs::directory_iterator dir_iter(directory_name, ec); std::vector<std::string> listFiles; - if (!DirectoryExists(directory_name)) { + + // In case the directory doesn't exist / can't be read, second check may be + // redundant + if (ec || !DirectoryExists(directory_name)) { return listFiles; } - int32_t return_code = 0; - DIR* directory = NULL; - struct dirent dir_element_; - struct dirent* dir_element = &dir_element_; - struct dirent* result = NULL; - - directory = opendir(directory_name.c_str()); - if (NULL != directory) { - return_code = readdir_r(directory, dir_element, &result); - - for (; NULL != result && 0 == return_code; - return_code = readdir_r(directory, dir_element, &result)) { - if (0 == strcmp(result->d_name, "..") || - 0 == strcmp(result->d_name, ".")) { - continue; - } - - listFiles.push_back(std::string(result->d_name)); - } - - closedir(directory); + for (auto& dirent : dir_iter) { + listFiles.push_back(dirent.path().filename().string()); } - return listFiles; } @@ -390,47 +360,42 @@ bool file_system::CreateFile(const std::string& path) { } } -uint64_t file_system::GetFileModificationTime(const std::string& path) { - struct stat info; - if (0 != stat(path.c_str(), &info)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Could not get file mod time: " << path); +time_t file_system::GetFileModificationTime(const std::string& path) { + error_code ec; + std::time_t time = fs::last_write_time(path, ec); + if (ec) { + return 0; } - return static_cast<uint64_t>(info.st_mtim.tv_nsec); + return time; } bool file_system::CopyFile(const std::string& src, const std::string& dst) { if (!FileExists(src) || FileExists(dst) || !CreateFile(dst)) { return false; } - std::vector<uint8_t> data; - if (!ReadBinaryFile(src, data) || !WriteBinaryFile(dst, data)) { - DeleteFile(dst); + error_code ec; + fs::copy_file(src, dst, ec); + if (ec) { + // something failed return false; } return true; } bool file_system::MoveFile(const std::string& src, const std::string& dst) { + error_code ec; + if (std::rename(src.c_str(), dst.c_str()) == 0) { return true; - } else { - // In case of src and dst on different file systems std::rename returns - // an error (at least on QNX). - // Seems, streams are not recommended for use, so have - // to find another way to do this. - std::ifstream s_src(src, std::ios::binary); - if (!s_src.good()) { - return false; - } - std::ofstream s_dst(dst, std::ios::binary); - if (!s_dst.good()) { - return false; - } - s_dst << s_src.rdbuf(); - s_dst.close(); - s_src.close(); - DeleteFile(src); - return true; } - return false; + // In case of src and dst on different file systems std::rename returns + // an error (at least on QNX). + // Instead, copy the file over and delete the old one + bool success = CopyFile(src, dst); + if (!success) { + return false; + } + DeleteFile(src); + + return true; } diff --git a/src/components/utils/src/lock_posix.cc b/src/components/utils/src/lock_boost.cc index 9b90ad20b9..2299bcf77d 100644 --- a/src/components/utils/src/lock_posix.cc +++ b/src/components/utils/src/lock_boost.cc @@ -30,117 +30,98 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "utils/lock.h" #include <errno.h> #include <stdint.h> -#include <stdio.h> #include <string.h> #include <cstring> +#include "utils/lock.h" #include "utils/logger.h" namespace sync_primitives { CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") -Lock::Lock() -#ifndef NDEBUG - : lock_taken_(0) - , is_mutex_recursive_(false) -#endif // NDEBUG -{ - Init(false); -} - -Lock::Lock(bool is_recursive) -#ifndef NDEBUG - : lock_taken_(0) - , is_mutex_recursive_(is_recursive) -#endif // NDEBUG -{ - Init(is_recursive); -} +Lock::Lock() : lock_taken_(0) {} Lock::~Lock() { -#ifndef NDEBUG if (lock_taken_ > 0) { - 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 " << &mutex_ << ": " - << strerror(status)); + LOG4CXX_FATAL(logger_, "Destroying non-released regular mutex " << &mutex_); } } void Lock::Acquire() { - const int32_t status = pthread_mutex_lock(&mutex_); - if (status != 0) { - LOG4CXX_FATAL(logger_, - "Failed to acquire mutex " << &mutex_ << ": " - << strerror(status)); - NOTREACHED(); - } else { - AssertFreeAndMarkTaken(); - } + mutex_.lock(); + AssertFreeAndMarkTaken(); } void Lock::Release() { AssertTakenAndMarkFree(); - const int32_t status = pthread_mutex_unlock(&mutex_); - if (status != 0) { - LOG4CXX_ERROR(logger_, - "Failed to unlock mutex" << &mutex_ << ": " - << strerror(status)); - } + mutex_.unlock(); } bool Lock::Try() { - const int32_t status = pthread_mutex_trylock(&mutex_); - if (status == 0) { -#ifndef NDEBUG - lock_taken_++; -#endif - return true; + bool status = mutex_.try_lock(); + if (status) { + AssertFreeAndMarkTaken(); } - return false; + return status; } -#ifndef NDEBUG void Lock::AssertFreeAndMarkTaken() { - if ((lock_taken_ > 0) && !is_mutex_recursive_) { - LOG4CXX_ERROR(logger_, "Locking already taken not recursive mutex"); + if (lock_taken_ != 0) { + LOG4CXX_FATAL(logger_, "Locking already taken not recursive mutex"); NOTREACHED(); } lock_taken_++; } + void Lock::AssertTakenAndMarkFree() { if (lock_taken_ == 0) { - LOG4CXX_ERROR(logger_, "Unlocking a mutex that is not taken"); + LOG4CXX_FATAL(logger_, "Unlocking a mutex that is not taken"); NOTREACHED(); } lock_taken_--; } -#endif -void Lock::Init(bool is_recursive) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); +// Recursive lock looks the same on the surface, some code duplication is +// necessary since they don't have a shared parent superclass +RecursiveLock::RecursiveLock() : lock_taken_(0) {} - const int32_t mutex_type = - is_recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_ERRORCHECK; +RecursiveLock::~RecursiveLock() { + if (lock_taken_ > 0) { + LOG4CXX_FATAL(logger_, + "Destroying non-released recursive mutex " << &mutex_); + } +} - pthread_mutexattr_settype(&attr, mutex_type); - const int32_t status = pthread_mutex_init(&mutex_, &attr); +void RecursiveLock::Acquire() { + mutex_.lock(); + AssertFreeAndMarkTaken(); +} - pthread_mutexattr_destroy(&attr); +void RecursiveLock::Release() { + AssertTakenAndMarkFree(); + mutex_.unlock(); +} - if (status != 0) { - LOG4CXX_FATAL(logger_, - "Failed to initialize mutex. " << std::strerror(status)); - DCHECK(status != 0); +bool RecursiveLock::Try() { + bool status = mutex_.try_lock(); + if (status) { + AssertFreeAndMarkTaken(); } + return status; +} + +void RecursiveLock::AssertFreeAndMarkTaken() { + lock_taken_++; +} + +void RecursiveLock::AssertTakenAndMarkFree() { + if (lock_taken_ == 0) { + LOG4CXX_FATAL(logger_, "Unlocking a recursive mutex that is not taken"); + NOTREACHED(); + } + lock_taken_--; } } // namespace sync_primitives diff --git a/src/components/utils/src/log_message_loop_thread.cc b/src/components/utils/src/log_message_loop_thread.cc index 2b7f28fbfd..182eb64534 100644 --- a/src/components/utils/src/log_message_loop_thread.cc +++ b/src/components/utils/src/log_message_loop_thread.cc @@ -35,7 +35,7 @@ namespace logger { -void LogMessageHandler::Handle(const LogMessage message) { +void LogMessageLoopThread::Handle(const LogMessage message) { message.logger->forcedLog(message.level, message.entry, message.timeStamp, @@ -44,14 +44,13 @@ void LogMessageHandler::Handle(const LogMessage message) { } LogMessageLoopThread::LogMessageLoopThread() - : LogMessageLoopThreadTemplate("Logger", - handler_ = new LogMessageHandler()) {} + : LogMessageLoopThreadTemplate("Logger", this) {} LogMessageLoopThread::~LogMessageLoopThread() { // we'll have to drop messages // while deleting logger thread logger_status = DeletingLoggerThread; - delete handler_; + LogMessageLoopThreadTemplate::Shutdown(); } } // namespace logger diff --git a/src/components/utils/src/logger.cc b/src/components/utils/src/logger.cc index 4e93ca3d14..af21aeac77 100644 --- a/src/components/utils/src/logger.cc +++ b/src/components/utils/src/logger.cc @@ -39,6 +39,9 @@ void deinit_logger() { CREATE_LOGGERPTR_LOCAL(logger_, "Utils") LOG4CXX_DEBUG(logger_, "Logger deinitialization"); logger::set_logs_enabled(false); + if (logger::logger_status == logger::LoggerThreadCreated) { + logger::flush_logger(); + } logger::delete_log_message_loop_thread(); log4cxx::LoggerPtr rootLogger = log4cxx::Logger::getRootLogger(); log4cxx::spi::LoggerRepositoryPtr repository = diff --git a/src/components/utils/src/semantic_version.cc b/src/components/utils/src/semantic_version.cc new file mode 100644 index 0000000000..9f0991e991 --- /dev/null +++ b/src/components/utils/src/semantic_version.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Livio + * 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/semantic_version.h" + +namespace utils { + +const SemanticVersion base_rpc_version(4, 5, 1); +const SemanticVersion rpc_version_5(5, 0, 0); + +} // namespace utils
\ No newline at end of file diff --git a/src/components/utils/src/signals_posix.cc b/src/components/utils/src/signals_posix.cc index 274c254716..e13dc04f40 100644 --- a/src/components/utils/src/signals_posix.cc +++ b/src/components/utils/src/signals_posix.cc @@ -29,13 +29,16 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/wait.h> #include <csignal> #include <cstdlib> #include <stdint.h> +#include <iostream> #include "utils/signals.h" -bool utils::UnsibscribeFromTermination() { +namespace utils { +bool Signals::UnsubscribeFromTermination() { // Disable some system signals receiving in thread // by blocking those signals // (system signals processes only in the main thread) @@ -51,6 +54,42 @@ bool utils::UnsibscribeFromTermination() { return !pthread_sigmask(SIG_BLOCK, &signal_set, NULL); } +bool Signals::UnsubscribeFromLowVoltageSignals( + const main_namespace::LowVoltageSignalsOffset& offset_data) { + // Disable Low Voltage signals in main thread + // due to all further threads will inherit signals mask + sigset_t signal_set; + sigemptyset(&signal_set); + const int SIGLOWVOLTAGE = SIGRTMIN + offset_data.low_voltage_signal_offset; + const int SIGWAKEUP = SIGRTMIN + offset_data.wake_up_signal_offset; + const int SIGIGNOFF = SIGRTMIN + offset_data.ignition_off_signal_offset; + sigaddset(&signal_set, SIGLOWVOLTAGE); + sigaddset(&signal_set, SIGWAKEUP); + sigaddset(&signal_set, SIGIGNOFF); + + // Set signals mask to be blocked by thread + return !pthread_sigmask(SIG_BLOCK, &signal_set, nullptr); +} + +void Signals::SendSignal(const int signo, const pid_t pid) { + if (kill(pid, signo) == -1) { + std::cerr << "Error sending signal: " << strsignal(signo) << " to " << pid + << " .Error: " << strerror(errno) << std::endl; + } +} + +pid_t Signals::Fork() { + return fork(); +} + +void Signals::ExitProcess(const int status) { + exit(status); +} + +void Signals::WaitPid(pid_t cpid, int* status, int options) { + waitpid(cpid, status, options); +} + namespace { bool CatchSIGSEGV(sighandler_t handler) { struct sigaction act; @@ -63,7 +102,7 @@ bool CatchSIGSEGV(sighandler_t handler) { } } // namespace -bool utils::WaitTerminationSignals(sighandler_t sig_handler) { +bool Signals::WaitTerminationSignals(sighandler_t sig_handler) { sigset_t signal_set; int sig = -1; @@ -81,3 +120,4 @@ bool utils::WaitTerminationSignals(sighandler_t sig_handler) { } return false; } +} // namespace utils diff --git a/src/components/utils/src/system_time_handler.cc b/src/components/utils/src/system_time_handler.cc new file mode 100644 index 0000000000..0c3c62cc53 --- /dev/null +++ b/src/components/utils/src/system_time_handler.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018, 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/system_time_handler.h" + +namespace utils { + +SystemTimeHandler::SystemTimeHandler() {} + +SystemTimeHandler::~SystemTimeHandler() {} + +void SystemTimeHandler::QuerySystemTime() { + DoSystemTimeQuery(); +} + +void SystemTimeHandler::SubscribeOnSystemTime(SystemTimeListener* listener) { + DoSubscribe(listener); +} + +void SystemTimeHandler::UnsubscribeFromSystemTime( + SystemTimeListener* listener) { + DoUnsubscribe(listener); +} + +time_t SystemTimeHandler::GetUTCTime() { + return FetchSystemTime(); +} + +bool SystemTimeHandler::system_time_can_be_received() const { + return utc_time_can_be_received(); +} + +} // namespace utils |