diff options
Diffstat (limited to 'src/components/utils')
36 files changed, 4153 insertions, 0 deletions
diff --git a/src/components/utils/CMakeLists.txt b/src/components/utils/CMakeLists.txt new file mode 100644 index 0000000000..12c70746d7 --- /dev/null +++ b/src/components/utils/CMakeLists.txt @@ -0,0 +1,64 @@ +set(UtilsIncludeDir ${CMAKE_SOURCE_DIR}/src/components/utils/include) + +include_directories ( + ./include + ../config_profile/include + ../media_manager/include/ + ../protocol_handler/include/ + ${LOG4CXX_INCLUDE_DIRECTORY} +) + +set (SOURCES + ./src/bitstream.cc + ./src/conditional_variable_posix.cc + ./src/file_system.cc + ./src/threads/posix_thread.cc + ./src/threads/thread_manager.cc + ./src/threads/thread_validator.cc + ./src/lock_posix.cc + ./src/rwlock_posix.cc + ./src/date_time.cc + ./src/signals_linux.cc + ./src/system.cc + ./src/resource_usage.cc + ./src/appenders_loader.cc +) + +if(ENABLE_LOG) + list(APPEND SOURCES + ./src/push_log.cc + ./src/log_message_loop_thread.cc + ./src/logger_status.cc + ) +endif() + +if (BUILD_BACKTRACE_SUPPORT) + list(APPEND SOURCES + ./src/back_trace.cc + ) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "QNX") + list(APPEND SOURCES + ./src/threads/pulse_thread_delegate.cc + ) +endif() + +add_library("Utils" ${SOURCES}) + +if(ENABLE_LOG) + list(APPEND LIBRARIES log4cxx -L${LOG4CXX_LIBS_DIRECTORY}) + list(APPEND LIBRARIES apr-1 -L${APR_LIBS_DIRECTORY}) + list(APPEND LIBRARIES aprutil-1 -L${APR_UTIL_LIBS_DIRECTORY}) + target_link_libraries("Utils" ${LIBRARIES}) + ADD_DEPENDENCIES(Utils install-3rd_party_logger) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries("Utils" pthread ${RTLIB}) +endif() + +if(BUILD_TESTS) + add_subdirectory(test) +endif() + diff --git a/src/components/utils/include/utils/appenders_loader.h b/src/components/utils/include/utils/appenders_loader.h new file mode 100644 index 0000000000..03d3217994 --- /dev/null +++ b/src/components/utils/include/utils/appenders_loader.h @@ -0,0 +1,51 @@ +/* + * 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_APPENDERS_LOADER_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_APPENDERS_LOADER_H_ + +namespace utils { + +class AppendersLoader { + public: + AppendersLoader(); + ~AppendersLoader(); + bool Loaded() const; + private: + void* handle_; +}; + +extern AppendersLoader appenders_loader; + +} // namespace utils + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_APPENDERS_LOADER_H_ diff --git a/src/components/utils/include/utils/back_trace.h b/src/components/utils/include/utils/back_trace.h new file mode 100644 index 0000000000..7f8912faf9 --- /dev/null +++ b/src/components/utils/include/utils/back_trace.h @@ -0,0 +1,75 @@ +/** + * 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. + */ +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_BACK_TRACE_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_BACK_TRACE_H_ + +#include <ostream> +#include <vector> +#include <string> +#include "utils/threads/thread.h" + +namespace utils { + +/* + * Class that captures stack trace in place where it was created. + * Can be stored and passed for further processing + * ostream output operator is available for these objects so stacktrace + * here and now can be easily printed as + * + * std::cout<<utils::Backtrace()<<std::endl; + */ +class Backtrace { + public: + // Inspect stack up to 128 calls back + static const int32_t kDefaultDepth = 128; + static const int32_t kSkipTop = 0; + /* Capture backtrace and store. Limit captured stack length to + * count symbols and remove first skip_top elements from it + * (to avoid polluting stack trace with debugging function names) + */ + Backtrace(int32_t count = kDefaultDepth, int32_t skip_top = kSkipTop); + ~Backtrace(); + + // Captured symbols in order from topmost stack frame to last captured + std::vector<std::string> CallStack() const; + threads::Thread::Id ThreadId() const; + + private: + threads::Thread::Id thread_id_; + std::vector<void*> backtrace_; +}; + +std::ostream& operator<< (std::ostream& os, const Backtrace& bt); + +} // namespace utils + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_BACK_TRACE_H_ diff --git a/src/components/utils/include/utils/bitstream.h b/src/components/utils/include/utils/bitstream.h new file mode 100644 index 0000000000..cba15abd8b --- /dev/null +++ b/src/components/utils/include/utils/bitstream.h @@ -0,0 +1,170 @@ +/** + * 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. + */ +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_BITSTREAM_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_BITSTREAM_H_ + +#include "stdint.h" + +#include <climits> +#include <cstring> +#include <string> +#include <vector> + +#include "utils/macro.h" + +namespace utils { + +// Big endian input bitstream class +// Tool to read and parse incoming data in a recursive way +// Has sublte similarity to standard stream classes in a way +// it handles stream parsing errors: +// If error while parsing stream occurs, whole stream is marked as +// "bad" and all subsequent parsing is stopped. +class BitStream { + public: + BitStream(uint8_t* bytes, size_t bytes_count); + ~BitStream(); + + // Mark stream as badly-formed. + // Should be called by Extract* family of procedures if they decide + // that stream is invalid + void MarkBad() { bad_ = true; } + // Predicates to check whether there were errors while parsing + // Stream is good when it is created + bool IsGood() { return !bad_; } + bool IsBad() { return bad_; } + operator bool() { return IsGood(); } + private: + // These two functions are used for internal stream checks only + // Stream parser procedures must not define their logic depending on + // amount of data left in particular bit stream + + // Amount of full bytes left in stream + size_t FullBytesLeft(); + // Amount of total bits left in stream + size_t BitsLeft(); + + // These stream extractors are helpers for direct friend extractors + // of this class. + + // Extract single value, amount of bits read from stream depends on T size + // If there is not enough data in the stream, stream is marked bad + template<typename T> + void Extract(T& val); + + // Read single value, amount of bits read from stream is signaled by |bits| + // parameter. T must be wide enough to hold this amount of bits. + // If there is not enough data in the stream, stream is marked bad + template<typename T> + void ExtractBits(T& val, size_t bits); + + // Extract |length| bytes from the stream. Stream read position + // must be byte aligned when it is called, stream is marked bad otherwise. + // If there is not enough data in the stream, it is marked bad. + void ExtractBytes(void* buffer, size_t length); + + private: + const uint8_t* bytes_; + const size_t bytes_count_; + size_t byte_offset_; + size_t bit_offset_; + bool bad_; + private: + friend void Extract(BitStream*, uint8_t*); + friend void Extract(BitStream*, uint8_t*, size_t); + friend void Extract(BitStream*, uint32_t*); + friend void Extract(BitStream*, uint32_t*, size_t); + friend void Extract(BitStream*, std::string*, size_t); + friend void Extract(BitStream*, std::vector<uint8_t>*, size_t); + +}; + +// Extract single byte from stream +// If there is not enough data in the stream it is marked bad. +void Extract(BitStream* bs, uint8_t* val); + +// Extract defined amount of |bits| from stream and store them +// in a byte size |val|. Hence |bits| must be less than 8. +void Extract(BitStream* bs, uint8_t* val, size_t bits); + +// Extract 32 bit word from stream. +// If there is not enough data in the stream it is marked bad. +void Extract(BitStream* bs, uint32_t* val); + +// Extract up to 32 |bits| from stream and store them in a |val| +// If there is not enough data in the stream it is marked bad. +void Extract(BitStream* bs, uint32_t* val, size_t bits); + +// Extract |length| bytes from stream and store them to the +// string |str|. If stream is too short it is marked bad. +// String must not contain zero bytes. +void Extract(BitStream* bs, std::string* str, size_t length); + +// Extract |length| bytes from stream and store them to the +// vector |data|. If stream is too short it is marked bad. +void Extract(BitStream* bs, std::vector<uint8_t>* data, size_t length); + + +// Template member definitions +template<typename T> +void BitStream::Extract(T& val) { + // Slow but simple implementation + // It's a space for bit stream reading optimization + ExtractBits(val, sizeof(val) * CHAR_BIT); +} + +template<typename T> +void BitStream::ExtractBits(T& val, size_t bits) { + DCHECK(sizeof(val) * CHAR_BIT >= bits); + if (IsGood()) { + if (bits > BitsLeft()) { + MarkBad(); + return; + } + val = T(); // Clear value + for (size_t i = 0; i < bits; ++i) { + size_t next_bit_number = CHAR_BIT - 1 - bit_offset_; + uint8_t nextbit = (bytes_[byte_offset_] >> next_bit_number) & 1; + val = (val << 1) | nextbit; + ++bit_offset_; + if (bit_offset_ == CHAR_BIT) { + ++byte_offset_; + bit_offset_ = 0; + } + } + } +} + +} // namespace utils + + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_BITSTREAM_H_ diff --git a/src/components/utils/include/utils/file_system.h b/src/components/utils/include/utils/file_system.h new file mode 100644 index 0000000000..d68ec484f9 --- /dev/null +++ b/src/components/utils/include/utils/file_system.h @@ -0,0 +1,241 @@ +/** + * 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. + */ + +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_FILE_SYSTEM_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_FILE_SYSTEM_H_ + +#include <string.h> +#include <stdint.h> +#include <string> +#include <vector> +#include <iostream> + +namespace file_system { + + +/** + * @brief Get available disc space. + * + * @param path to directory + * @return free disc space. + */ +uint64_t GetAvailableDiskSpace(const std::string& path); + +/* + * @brief Get size of current directory + * + * @param path to directory + */ +size_t DirectorySize(const std::string& path); + +/* + * @brief Get size of current file + * + * @param path to file + * @return size of file, return 0 if file not exist + */ +int64_t FileSize(const std::string& path); + +/** + * @brief Creates directory + * @param name path to directory + * @return path to created directory. + */ +std::string CreateDirectory(const std::string& name); + +/** + * @brief Creates directory recursively + * @param path - full path to directory + * @return return true if directory was created or already exist + */ +bool CreateDirectoryRecursively(const std::string& path); + +/** + * @brief Checks the file to see whether the file is a directory + * @param name path to file + * @return returns true if file is directory. + */ +bool IsDirectory(const std::string& name); + +/** + * @brief Is directory exist + * @param name path to directory + * @return returns true if directory is exists. + */ +bool DirectoryExists(const std::string& name); + +/** + * @brief Is file exist + * @param name path to file + * @return returns true if file is exists. + */ +bool FileExists(const std::string& name); + +/** + * @brief Writes to file + * + * @remark - create file if it doesn't exist + * @param name path to file + * @param data data to write + * @return returns true if the operation is successfully. + */ +bool Write(const std::string& file_name, + const std::vector<uint8_t>& data, + std::ios_base::openmode mode = std::ios_base::out); + +/** + * @brief Opens file stream for writing + * @param file_name path to file to write data to + * @return returns pointer to opened stream in case of success; + * otherwise returns NULL + */ +std::ofstream* Open(const std::string& file_name, + std::ios_base::openmode mode = std::ios_base::out); + +/** + * @brief Writes to file stream + * @param file_stream file stream to be written to + * @param data data to be written to file + * @param data_size size of data to be written to file + * @return returns true if the operation is successfully. + */ +bool Write(std::ofstream* const file_stream, + const uint8_t* data, + uint32_t data_size); + +/** + * @brief Closes file stream + * @param file_stream file stream to be closed + */ +void Close(std::ofstream* file_stream); + +/** + * @brief Returns current working directory path + * If filename begins with "/", return unchanged filename + * @param name file name + * @return returns full file path. + */ +std::string CurrentWorkingDirectory(); + +/** + * @brief Removes file + * + * @param name path to file + * @return returns true if the file is successfully deleted. + */ +bool DeleteFile(const std::string& name); + +/** + * @brief Removes directory. + * + * @param name path to directory. + * @param is_recursively true if you need delete directory recursively, otherwise false. + * @return returns true if the directory is successfully deleted. + */ +bool RemoveDirectory(const std::string& directory_name, + bool is_recursively = true); + +/** + * @brief Check access rights + * + * @param name path to file. + * @param how Read/write attribute. + * @return returns true if file has the given mode. + */ +bool IsAccessible(const std::string& name, int32_t how); + +/** + * @brief Check access rights for writing + * + * @param name path to file or folder + * @return returns true if has access rights. + */ +bool IsWritingAllowed(const std::string& name); + +/** + * @brief Check access rights for reading + * + * @param name path to file. + * @return returns true if file has access rights. + */ +bool IsReadingAllowed(const std::string& name); + +/** + * @brief Lists all files in given directory + * + * @param name path to directory. + * @return returns list of files. + */ +std::vector<std::string> ListFiles(const std::string& directory_name); + +/** + * @brief Creates or overwrites file with given binary contents + * @param name path to the file + * @param contents data to be written into the file + * @returns true if file write succeeded + */ +bool WriteBinaryFile(const std::string& name, + const std::vector<uint8_t>& contents); + +/** + * @brief Reads from file + * + * @param name path to file + * @param result read data + * @return returns true if the operation is successfully. + */ +bool ReadBinaryFile(const std::string& name, + std::vector<uint8_t>& result); + +bool ReadFile(const std::string& name, std::string& result); + +/** + * @brief Convert special symbols in system path to percent-encoded + * + * @param name path to file + * @return returns converted path. +*/ +const std::string ConvertPathForURL(const std::string& path); + +/** + * @brief Create empty file + * + * @param name path to file + * @return if result success return true +*/ +bool CreateFile(const std::string& path); + +void remove_directory_content(const std::string& directory_name); + +} // namespace file_system + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_FILE_SYSTEM_H_ diff --git a/src/components/utils/include/utils/log_message_loop_thread.h b/src/components/utils/include/utils/log_message_loop_thread.h new file mode 100644 index 0000000000..b23a246e13 --- /dev/null +++ b/src/components/utils/include/utils/log_message_loop_thread.h @@ -0,0 +1,80 @@ +/* + * 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_LOG_MESSAGE_LOOP_THREAD_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOG_MESSAGE_LOOP_THREAD_H_ + +#include <string> +#include <queue> +#include <log4cxx/logger.h> + +#include "utils/threads/message_loop_thread.h" +#include "utils/singleton.h" + +namespace logger { + +typedef struct { + log4cxx::LoggerPtr logger; + log4cxx::LevelPtr level; + std::string entry; + log4cxx_time_t timeStamp; + log4cxx::spi::LocationInfo location; + log4cxx::LogString threadName; +} LogMessage; + +typedef std::queue<LogMessage> LogMessageQueue; + +typedef threads::MessageLoopThread<LogMessageQueue> LogMessageLoopThreadTemplate; + +class LogMessageHandler : public LogMessageLoopThreadTemplate::Handler { + public: + virtual void Handle(const LogMessage message) OVERRIDE; +}; + +class LogMessageLoopThread : + public LogMessageLoopThreadTemplate, + public utils::Singleton<LogMessageLoopThread> { + + public: + ~LogMessageLoopThread(); + + private: + LogMessageLoopThread(); + +DISALLOW_COPY_AND_ASSIGN(LogMessageLoopThread); +FRIEND_BASE_SINGLETON_CLASS(LogMessageLoopThread); + +}; + +} // namespace logger + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_LOG_MESSAGE_LOOP_THREAD_H_ diff --git a/src/components/utils/include/utils/resource_usage.h b/src/components/utils/include/utils/resource_usage.h new file mode 100644 index 0000000000..a8fa4aa7d9 --- /dev/null +++ b/src/components/utils/include/utils/resource_usage.h @@ -0,0 +1,168 @@ +/** + * 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_RESOURCE_USAGE_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RESOURCE_USAGE_H_ + +#include <sys/resource.h> +#if defined(__QNXNTO__) +#include <sys/procfs.h> +#endif + +#include <string> +#include <iostream> + +#include "utils/logger.h" + +#define MAX_COMM_LEN 128 +#define MAX_CMDLINE_LEN 128 + +namespace utils { + +struct ResourseUsage { + long long int utime; + long long int stime; + long long int memory; +}; + +class Resources { + public: + typedef uint32_t MemInfo; +#if defined(__QNXNTO__) + typedef procfs_info PidStats; + +#elif defined(OS_LINUX) + + struct PidStats { + int pid; + char comm[MAX_COMM_LEN]; + char state; + int ppid; + int pgrp; + int session; + int tty_nr; + int tpgid; + unsigned int flags; + unsigned long minflt; + unsigned long cminflt; + unsigned long majflt; + unsigned long cmajflt; + unsigned long utime; + long stime; + long cutime; + long cstime; + long priority; + long nice; + long num_threads; + long itrealvalue; + unsigned long long starttime; + unsigned long vsize; + long rss; + unsigned long rsslim; + unsigned long startcode; + unsigned long endcode; + unsigned long startstack; + unsigned long kstkesp; + unsigned long kstkeip; + unsigned long signal; + unsigned long blocked; + unsigned long sigignore; + unsigned long sigcatch; + unsigned long wchan; + unsigned long nswap; + unsigned long cnswap; + int exit_signal; + int processor; + unsigned int rt_priority; + unsigned int policy; + unsigned long long delayacct_blkio_ticks; + unsigned long guest_time; + long int cguest_time; + }; +#else + +#endif + public: + /* + * @brief Returns current resource usage of process + * @return Raw pointer on ResourseUsage if success, otherwise return NULL + */ + static ResourseUsage* getCurrentResourseUsage(); + +private: + + /* + * @brief reads /proc/PID/stat file on linux + * do not work on QNX ( return false, output wan't be changed ) + * @param output - storage for result string ( there will be separated content of /proc/PID/stat ) + * @return true on succes false onb fail + */ + static bool ReadStatFile(std::string& output); + + /* + * @brief Grab information about curent process + * @param output - storage for result struct + * @return true on succes false onb fail + */ + static bool GetProcInfo(PidStats& output); + + /* + * @brief Grab process memory information + * @param output - storage for result struct + * @return true on succes false onb fail + */ + static bool GetMemInfo(MemInfo& output); + + /* + * @brief return path to /proc/PID/stat file on linux + * return path to /proc/PID/as file on linux + * @return path to file + */ + static std::string GetStatPath(); + + /* + * @brief return path to /proc/PID directry + * @return path to dir + */ + static std::string GetProcPath(); + + /* + * path to /proc/ directory + */ + static const char* proc; +}; + +} + + + +#endif /* SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RESOURCE_USAGE_H_ */ diff --git a/src/components/utils/include/utils/signals.h b/src/components/utils/include/utils/signals.h new file mode 100644 index 0000000000..28e8afd9d6 --- /dev/null +++ b/src/components/utils/include/utils/signals.h @@ -0,0 +1,41 @@ +/* +* 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_ + +namespace utils { +bool SubscribeToTerminateSignal(void (*func)(int32_t p)); +bool ResetSubscribeToTerminateSignal(); +} // 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 new file mode 100644 index 0000000000..d7b625e0a1 --- /dev/null +++ b/src/components/utils/include/utils/singleton.h @@ -0,0 +1,179 @@ +/* + * 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. +*/ + +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_ + +#include "utils/lock.h" +#include "utils/memory_barrier.h" +#include "utils/atomic.h" + +namespace utils { + +namespace deleters { + +class DummyDeleter { + public: + void grab(void* pointer) { + } +}; + +template<typename T> +class Deleter { + public: + Deleter() : pointer_(0) { + } + ~Deleter() { + if (pointer_) { + delete pointer_; + } + } + void grab(T* pointer) { + pointer_ = pointer; + } + private: + T* pointer_; +}; + +} // namespace deleters + +template<typename T, class Deleter = deleters::DummyDeleter> +class Singleton { +/** + * @brief Singleton template + * Singleton classes must derive from this template specialized with class itself: + * + * class MySingleton : public Singleton<MySingleton> {...}; + * + * All such classes must declare instance() method as friend + * by adding FRIEND_BASE_SINGLETON_CLASS macro from macro.h to class definition: + * + * FRIEND_BASE_SINGLETON_CLASS(MySingleton); + * + * Instance of this class (if created) can be deleted by Deleter destructor + * which is called after main() (or from exit()) + * This requires T destructor to be accessible for Deleter (e.g. public) + * Deleter template parameter can be specified with any class + * with public default constructor, destructor and method + * void grab(T*); + * However, default Deleter specification does nothing + * + * Also instance can be deleted explicitly by calling destroy() method + * + * Both instance() and destroy() methods are thread safe + * but not thread safety between simultaneous calls + * of instance() and destroy() is cared about + */ + public: +/** + * @brief Returns the singleton of class + */ + static T* instance(); +/** + * @brief Destroys the singleton (if it had been created) + */ + static void destroy(); +/** + * @brief Checks whether the singleton exists + */ + static bool exists(); + + private: + + static T** instance_pointer(); + static Deleter* deleter(); +}; + +template<typename T, class Deleter> +T* Singleton<T, Deleter>::instance() { + static sync_primitives::Lock lock; + + T* local_instance; + atomic_pointer_assign(local_instance, *instance_pointer()); + memory_barrier(); + + if (!local_instance) { + lock.Acquire(); + local_instance = *instance_pointer(); + if (!local_instance) { + local_instance = new T(); + memory_barrier(); + atomic_pointer_assign(*instance_pointer(), local_instance); + deleter()->grab(local_instance); + } + lock.Release(); + } + + return local_instance; +} + +template<typename T, class Deleter> +void Singleton<T, Deleter>::destroy() { + static sync_primitives::Lock lock; + + T* local_instance; + atomic_pointer_assign(local_instance, *instance_pointer()); + memory_barrier(); + + if (local_instance) { + lock.Acquire(); + local_instance = *instance_pointer(); + if (local_instance) { + atomic_pointer_assign(*instance_pointer(), 0); + memory_barrier(); + delete local_instance; + deleter()->grab(0); + } + lock.Release(); + } +} + +template<typename T, class Deleter> +bool Singleton<T, Deleter>::exists() { + return *instance_pointer() != 0; +} + +template<typename T, class Deleter> +T** Singleton<T, Deleter>::instance_pointer() { + static T* instance = 0; + return &instance; +} + +template<typename T, class Deleter> +Deleter* Singleton<T, Deleter>::deleter() { + static Deleter deleter; + return &deleter; +} + +} // namespace utils + +#endif // 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 new file mode 100644 index 0000000000..f525c6429f --- /dev/null +++ b/src/components/utils/include/utils/stl_utils.h @@ -0,0 +1,81 @@ +/** + * 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. + */ +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_STL_UTILS_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_STL_UTILS_H_ + +#include "utils/macro.h" + +namespace utils { + +/* + * Utility class that automatically deletes STL collection of + * freestore objects + */ +template<class T> +class StlCollectionDeleter { + public: + typedef T Collection; + StlCollectionDeleter(T* collection): collection_(collection) { + DCHECK(collection_); + } + ~StlCollectionDeleter() { + for (typename Collection::iterator i = collection_->begin(), + end = collection_->end(); + i != end; ++i) { + delete *i; + } + } + private: + Collection* collection_; +}; + +template<class T> +class StlMapDeleter { + public: + typedef T Collection; + StlMapDeleter(T* collection): collection_(collection) { + DCHECK(collection_); + } + ~StlMapDeleter() { + for (typename Collection::iterator i = collection_->begin(), + end = collection_->end(); + i != end; ++i) { + delete i->second; + } + } + private: + Collection* collection_; +}; + +} // namespace utils + +#endif /* SRC_COMPONENTS_UTILS_INCLUDE_UTILS_STL_UTILS_H_ */ diff --git a/src/components/utils/include/utils/system.h b/src/components/utils/include/utils/system.h new file mode 100644 index 0000000000..16bdc03673 --- /dev/null +++ b/src/components/utils/include/utils/system.h @@ -0,0 +1,93 @@ +/** + * 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_SYSTEM_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_H_ + +#include <string> +#include <vector> + +namespace utils { + +/** + * Class to execute shell scripts + */ +class System { + public: + /** + * Constructs instantiation + * @param command name of command for executing + */ + explicit System(const std::string& command); + + /** + * Constructs instantiation + * @param file name of file for executing + * @param command name of command + */ + System(const std::string& file, const std::string& command); + + /** + * Adds argument + * @param arg argument of command + * @return itself object + */ + System& Add(const std::string& arg); + + /** + * Executes command as new child process + * @return true if success + */ + bool Execute(); + + /** + * Executes command + * @param wait if this flag is true then wait until command is terminated + * @return true if success + */ + bool Execute(bool wait); + + private: + /** + * Command for executing + */ + std::string command_; + + /** + * List of arguments + */ + std::vector<std::string> argv_; +}; + +} // utils + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_H_ diff --git a/src/components/utils/include/utils/threads/pulse_thread_delegate.h b/src/components/utils/include/utils/threads/pulse_thread_delegate.h new file mode 100644 index 0000000000..bb109bde94 --- /dev/null +++ b/src/components/utils/include/utils/threads/pulse_thread_delegate.h @@ -0,0 +1,96 @@ +/* + * 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_THREADS_PULSE_THREAD_DELEGATE_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_THREADS_PULSE_THREAD_DELEGATE_H_ + +#include <sys/neutrino.h> + +#include "utils/threads/thread_delegate.h" + +namespace threads { + +/** + * @brief This ThreadDelegate derivative is designed + * to implement threads waiting for QNX Pulse messages + * When constucted, an instance of this class creates QNX channel and connects to it + * In exitThreadMain() channel is disconnected and destroyed + * In threadMain() endless loop event is armed via pure virtual method ArmEvent() + * and thread blocks on MsgReceivePulse() waiting for Pulse + * When Pulse comes, OnPulse() pure virtual method is invoked + * Subclassed must implement ArmEvent() for events of interest + * and OnPulse() for reaction on such events + */ +class PulseThreadDelegate : public ThreadDelegate { + public: +/** + * @brief default constructor + */ + PulseThreadDelegate(); + virtual void threadMain(); + virtual bool exitThreadMain(); + + protected: +/** + * @brief This method is to be implemented to arm events of interest + * @param event pointer to structure sigevent + * @return If this method returns true, thread is blocked on MsgReceivePulse() waiting for Pulse + */ + virtual bool ArmEvent(struct sigevent* event) = 0; +/** + * @brief This method is invoked from threadMain() when Pulse comes + */ + virtual void OnPulse() = 0; + + /** + * This method is to be initialize child class + * @return If this method returns false, thread will be stopped + */ + virtual bool Init() { return true; } + +/** + * Finalizes thread + * Can free resources + */ + virtual void Finalize() {} + + private: + enum {PULSE_CODE = _PULSE_CODE_MINAVAIL + 1}; + + bool run_; + int chid_; + int coid_; +}; + +} // namespace threads + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_THREADS_PULSE_THREAD_DELEGATE_H_ diff --git a/src/components/utils/include/utils/threads/thread_manager.h b/src/components/utils/include/utils/threads/thread_manager.h new file mode 100644 index 0000000000..03330170e1 --- /dev/null +++ b/src/components/utils/include/utils/threads/thread_manager.h @@ -0,0 +1,117 @@ +/** + * 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. + */ + +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_THREADS_THREAD_MANAGER_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_THREADS_THREAD_MANAGER_H_ + +#include "utils/threads/thread.h" +#include "utils/lock.h" + +#include <map> +#include <string> +#include <set> + +#include "utils/macro.h" +#include "utils/singleton.h" + +namespace threads { +namespace impl { + +/* + * Generates short and unique names for unnamed threads + * and remembers association between thread handle and that short name + */ +class UnnamedThreadRegistry { + public: + UnnamedThreadRegistry(); + ~UnnamedThreadRegistry(); + /* + * Returns a name for given unnamed thread id. + * If id is first seen, new name is generated and memorized + * If id is already known, previously generated name is returned + */ + std::string GetUniqueName(PlatformThreadHandle id); + private: + typedef std::map<PlatformThreadHandle, std::string> IdNameMap; + IdNameMap id_number_; + int32_t last_thread_number_; + sync_primitives::Lock state_lock_; +}; + +/* + * This class is here currently to remember names associated to threads. + * It manages raw impl::PlatformHandles because Thread::Id's do not provide + * comparison operator. Current linux implementation relies on fact that + * pthread_t is just an integer and every thread has single unique value + * associated with it. + * OS provides it's own facilities to name threads but + */ +class ThreadManager : public utils::Singleton<ThreadManager> { + public: + // Name a thread. Should be called only once for every thread. + // Threads can't be renamed + void RegisterName(PlatformThreadHandle id, const std::string& name); + + // Get a name for previously registered thread + std::string GetName(PlatformThreadHandle id) const; + + // Forget a name of (possibly destroyed) thread + // Make sure to call it after thread is finished + // Because thread id's can be recycled + void Unregister(PlatformThreadHandle id); + private: + ThreadManager(); + ~ThreadManager(); + + private: + typedef std::set<std::string> NamesSet; + typedef std::map<PlatformThreadHandle, std::string> IdNamesMap; + // Set of thread names for fast checking if name is unique + NamesSet names_; + // Map from system handle to the thread name + IdNamesMap id_names_; + mutable sync_primitives::Lock state_lock_; + + // Generator of shorter sequental names for unnamed threads + // Has to memorize every generated name this is why it is mutable + mutable UnnamedThreadRegistry unnamed_thread_namer_; + + private: + DISALLOW_COPY_AND_ASSIGN(ThreadManager); + + FRIEND_BASE_SINGLETON_CLASS(ThreadManager); +}; + +} // namespace impl +} // namespace threads + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_THREADS_THREAD_MANAGER_H_ diff --git a/src/components/utils/include/utils/threads/thread_validator.h b/src/components/utils/include/utils/threads/thread_validator.h new file mode 100644 index 0000000000..def1994b76 --- /dev/null +++ b/src/components/utils/include/utils/threads/thread_validator.h @@ -0,0 +1,105 @@ +/** + * 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. + */ +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_THREADS_THREAD_VALIDATOR_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_THREADS_THREAD_VALIDATOR_H_ + +#include "utils/threads/thread.h" + +namespace threads { +/* + * Use objects of this class to validate (in run-time) access + * to single-threaded objects. It remembers the thread it was + * created on and then allows to easily check whether an object is + * being accessed from different thread and log an error in that case + * + * Put a member of type SingleThreadValidator in your class and call + * AssertRunningOnCreationThread in it's every public method + * + * class MySingleThreadedThing { + * ..... + * public: + * void DoSomeWork(); + * ..... + * private: + * SingleThreadValidator thread_validator_; + * ..... + * }; + * + * void MySingleThreadedThing::DoSomeWork() { + * thread_validator_.AssertRunningOnCreationThread(); + * ..... + * } + */ +class SingleThreadSimpleValidator { + public: + SingleThreadSimpleValidator(); + ~SingleThreadSimpleValidator(); + + // This method should be called in every public method + // of classes being checked for absence of concurrent access + void AssertRunningOnCreationThread() const; + private: + const Thread::Id creation_thread_id_; +}; + + +/* + * This is bit more sophisticated debug helper which allows + * objects being checked to be transferred between threads. + * Make sure to pass ownership calling PassToThread before + * object is accessed from that thread! + * + * It's better to virtually inherit it to make PassToThread publicly + * available to code that uses objects of your classes and make sure + * that if your object consists of different thread-validated + * parts you'll need not to call PassToThread proxy method for + * every part of your composite object + */ +class SingleThreadValidator { + public: + SingleThreadValidator(); + ~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; + // 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_; +}; + +} // namespace threads + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_THREADS_THREAD_VALIDATOR_H_ diff --git a/src/components/utils/src/appenders_loader.cc b/src/components/utils/src/appenders_loader.cc new file mode 100644 index 0000000000..cbbd039060 --- /dev/null +++ b/src/components/utils/src/appenders_loader.cc @@ -0,0 +1,55 @@ +/* + * 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 <dlfcn.h> + +#include "utils/appenders_loader.h" + +namespace utils { + +AppendersLoader appenders_loader; + +AppendersLoader::AppendersLoader() { + handle_ = dlopen("libappenders.so", RTLD_LAZY | RTLD_NODELETE); +} + +AppendersLoader::~AppendersLoader() { + if (handle_ != 0) { + dlclose(handle_); + } +} + +bool AppendersLoader::Loaded() const { + return handle_ != 0; +} + +} // namespace utils diff --git a/src/components/utils/src/back_trace.cc b/src/components/utils/src/back_trace.cc new file mode 100644 index 0000000000..23b1b4d1e9 --- /dev/null +++ b/src/components/utils/src/back_trace.cc @@ -0,0 +1,107 @@ +/** + * 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/back_trace.h" + +#include <algorithm> +#include <vector> +#include <sstream> + +#include <cxxabi.h> +#include <execinfo.h> + +#include "utils/macro.h" + +using std::ostream; +using std::string; +using std::vector; +using threads::Thread; + +namespace utils { + +namespace { +string demangle(const char* symbol) { + char temp[2048]; + if (1 == sscanf(symbol, "%*[^(]%*[^_]%2047[^)+]", temp)) { + size_t size; + int32_t status; + char* demangled = abi::__cxa_demangle(temp, NULL, &size, &status); + if (demangled != NULL) { + string result(demangled); + free(demangled); + return result; + } + } + return symbol; +} +} + +Backtrace::Backtrace(int32_t count, int32_t skip_top) + : thread_id_(threads::Thread::CurrentId()) { + int32_t skip = skip_top + 1; // Skip this constructor + vector<void*> full_trace (count + skip); + int32_t captured = backtrace(&full_trace.front(), count + skip); + int32_t first_call = std::min(captured, skip); + int32_t last_call = std::min(first_call + count, captured); + backtrace_.assign(full_trace.begin() + first_call, full_trace.begin() + last_call); +} + +Backtrace::~Backtrace() { +} + +vector<string> Backtrace::CallStack() const { + vector<string> callstack; + callstack.reserve(backtrace_.size()); + char** mangled = backtrace_symbols(&backtrace_.front(), backtrace_.size()); + for (size_t i = 0; i != backtrace_.size(); ++i) { + callstack.push_back(demangle(mangled[i])); + } + free(mangled); + return callstack; +} + +Thread::Id Backtrace::ThreadId() const { + return thread_id_; +} + +ostream& operator<< (ostream& os, const Backtrace& bt) { + const vector<string> symbols = bt.CallStack(); + os<<"Stack trace ("<<bt.ThreadId()<<")\n"; + if (symbols.empty()) { + os<<"Not available"<<std::endl; + } else for (size_t i = 0; i < symbols.size(); ++i) { + os<<symbols[i]<<std::endl; + } + return os; +} + +} // namespace utils diff --git a/src/components/utils/src/bitstream.cc b/src/components/utils/src/bitstream.cc new file mode 100644 index 0000000000..c616b1ae4a --- /dev/null +++ b/src/components/utils/src/bitstream.cc @@ -0,0 +1,132 @@ +/** + * 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/bitstream.h" + +namespace utils { + +BitStream::BitStream(uint8_t* bytes, size_t bytes_count) + : bytes_(bytes), + bytes_count_(bytes_count), + byte_offset_(0), + bit_offset_(0), + bad_(false) { +} + +BitStream::~BitStream() { +} + +size_t BitStream::FullBytesLeft() { + size_t left = bytes_count_ - byte_offset_; + if (bit_offset_ != 0) + left -= 1; + return left; +} + +size_t BitStream::BitsLeft() { + return (bytes_count_ - byte_offset_) * CHAR_BIT - bit_offset_; +} + +void BitStream::ExtractBytes(void* buffer, size_t length) { + DCHECK(length == 0 || buffer != NULL); + if (IsGood()) { + if (bit_offset_ != 0 || // bytes can be extracted only when + FullBytesLeft() < length) { // stream is byte-aligned + MarkBad(); + return; + } + } + memcpy(buffer, &bytes_[byte_offset_], length); + byte_offset_ += length; +} + +void Extract(BitStream* bs, uint8_t* val) { + DCHECK(bs && val); + if (*bs) { + bs->Extract(*val); + } +} + +void Extract(BitStream* bs, uint8_t* val, size_t bits) { + DCHECK(bs && val); + if (*bs) { + bs->ExtractBits(*val, bits); + } +} + +void Extract(BitStream* bs, uint32_t* val) { + DCHECK(bs && val); + if (*bs) { + bs->Extract(*val); + } +} + +void Extract(BitStream* bs, uint32_t* val, size_t bits) { + DCHECK(bs && val); + if (*bs) { + bs->ExtractBits(*val, bits); + } +} + +void Extract(BitStream* bs, std::string* str, size_t length) { + DCHECK(bs && str); + if (*bs) { + // Prevent memory over-allocation + if (bs->FullBytesLeft() < length) { + bs->MarkBad(); + return; + } + str->resize(length+1); + void* stringdata = &(*str)[0]; + bs->ExtractBytes(stringdata, length); + str->resize(length); + } +} + +void Extract(BitStream* bs, std::vector<uint8_t>* data, size_t length) { + DCHECK(bs && data); + if (*bs) { + // Prevent memory over-allocation + if (bs->FullBytesLeft() < length) { + bs->MarkBad(); + return; + } + data->resize(length); + + if (0 != length) { + void* dataptr = &data->front(); + bs->ExtractBytes(dataptr, length); + } + } +} + +} // namespace utils + diff --git a/src/components/utils/src/conditional_variable_posix.cc b/src/components/utils/src/conditional_variable_posix.cc new file mode 100644 index 0000000000..a89f8cab65 --- /dev/null +++ b/src/components/utils/src/conditional_variable_posix.cc @@ -0,0 +1,136 @@ +/** + * 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; + int32_t 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"); + int32_t 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() { + int32_t signaled = pthread_cond_signal(&cond_var_); + if (signaled != 0) + LOG4CXX_ERROR(logger_, "Failed to signal conditional variable"); + +} + +void ConditionalVariable::Broadcast() { + int32_t signaled = pthread_cond_broadcast(&cond_var_); + if (signaled != 0) + LOG4CXX_ERROR(logger_, "Failed to broadcast conditional variable"); + +} + +void 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) + LOG4CXX_ERROR(logger_, "Failed to wait for conditional variable"); +} + +ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( + AutoLock& auto_lock, int32_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(); + int32_t 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 new file mode 100644 index 0000000000..f190951647 --- /dev/null +++ b/src/components/utils/src/date_time.cc @@ -0,0 +1,102 @@ +/* +* 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; + + gettimeofday(¤tTime, &timeZone); + + return currentTime; +} + +int64_t date_time::DateTime::getSecs(const TimevalStruct &time) { + return static_cast<int64_t>(time.tv_sec); +} + +int64_t DateTime::getmSecs(const TimevalStruct &time) { + return static_cast<int64_t>(time.tv_sec) * MILLISECONDS_IN_SECOND + + time.tv_usec / MICROSECONDS_IN_MILLISECONDS; +} + +int64_t DateTime::getuSecs(const TimevalStruct &time) { + return static_cast<int64_t>(time.tv_sec) * MILLISECONDS_IN_SECOND + * MICROSECONDS_IN_MILLISECONDS + time.tv_usec; +} + +int64_t DateTime::calculateTimeSpan(const TimevalStruct& sinceTime) { + return calculateTimeDiff(getCurrentTime(), sinceTime); +} + +int64_t DateTime::calculateTimeDiff(const TimevalStruct &time1, + const TimevalStruct &time2){ + TimevalStruct ret; + if (Greater(time1, time2)) { + ret = Sub(time1, time2); + } else { + ret = Sub(time2, time1); + } + return getmSecs(ret); +} + +TimevalStruct DateTime::Sub(const TimevalStruct& time1, + const TimevalStruct& time2) { + TimevalStruct ret; + timersub(&time1, &time2, &ret); + return ret; +} + +bool DateTime::Greater(const TimevalStruct& time1, const TimevalStruct& time2) { + return timercmp(&time1, &time2, >); +} + +bool DateTime::Less(const TimevalStruct& time1, const TimevalStruct& time2) { + return timercmp(&time1, &time2, <); +} + +bool DateTime::Equal(const TimevalStruct& time1, const TimevalStruct& time2) { + return !timercmp(&time1, &time2, !=); +} + +TimeCompare date_time::DateTime::compareTime(const TimevalStruct &time1, const TimevalStruct &time2) { + if (Greater(time1, time2)) return GREATER; + if (Less(time1, time2)) return LESS; + return EQUAL; +} + +} // namespace date_time diff --git a/src/components/utils/src/file_system.cc b/src/components/utils/src/file_system.cc new file mode 100644 index 0000000000..5eb2457a09 --- /dev/null +++ b/src/components/utils/src/file_system.cc @@ -0,0 +1,423 @@ +/* + * 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/file_system.h" +#include "utils/logger.h" + +#include <sys/statvfs.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sstream> + +#include <dirent.h> +#include <unistd.h> +// TODO(VS): lint error: Streams are highly discouraged. +#include <fstream> +#include <cstddef> +#include <algorithm> + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +uint64_t file_system::GetAvailableDiskSpace(const std::string& path) { + struct statvfs fsInfo; + memset(reinterpret_cast<void*>(&fsInfo), 0, sizeof(fsInfo)); + if (statvfs(path.c_str(), &fsInfo) == 0) { + return fsInfo.f_bsize * fsInfo.f_bfree; + } else { + return 0; + } +} + +int64_t file_system::FileSize(const std::string &path) { + if (file_system::FileExists(path)) { + struct stat file_info; + memset(reinterpret_cast<void*>(&file_info), 0, sizeof(file_info)); + stat(path.c_str(), &file_info); + return file_info.st_size; + } + return 0; +} + +size_t file_system::DirectorySize(const std::string& path) { + size_t size = 0; + int32_t return_code = 0; + DIR* directory = NULL; + +#ifndef __QNXNTO__ + struct dirent dir_element_; + struct dirent* dir_element = &dir_element_; +#else + char* direntbuffer = + new char[offsetof(struct dirent, d_name) + + pathconf(path.c_str(), _PC_NAME_MAX) + 1]; + struct dirent* dir_element = new(direntbuffer) dirent; +#endif + struct dirent* result = NULL; + struct stat file_info; + 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 { + memset(reinterpret_cast<void*>(&file_info), 0, sizeof(file_info)); + stat(full_element_path.c_str(), &file_info); + size += file_info.st_size; + } + } + } + closedir(directory); +#ifdef __QNXNTO__ + delete[] direntbuffer; +#endif + return size; +} + +std::string file_system::CreateDirectory(const std::string& name) { + if (!DirectoryExists(name)) { + mkdir(name.c_str(), S_IRWXU); + } + + 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; + } + } + } + + return ret_val; +} + +bool file_system::IsDirectory(const std::string& name) { + struct stat status; + memset(&status, 0, sizeof(status)); + + if (-1 == stat(name.c_str(), &status)) { + return false; + } + + return S_ISDIR(status.st_mode); +} + +bool file_system::DirectoryExists(const std::string& name) { + struct stat status; + memset(&status, 0, sizeof(status)); + + if (-1 == stat(name.c_str(), &status) || !S_ISDIR(status.st_mode)) { + return false; + } + + return true; +} + +bool file_system::FileExists(const std::string& name) { + struct stat status; + memset(&status, 0, sizeof(status)); + + if (-1 == stat(name.c_str(), &status)) { + return false; + } + return true; +} + +bool file_system::Write( + const std::string& file_name, const std::vector<uint8_t>& data, + std::ios_base::openmode mode) { + std::ofstream file(file_name.c_str(), std::ios_base::binary | mode); + if (file.is_open()) { + for (uint32_t i = 0; i < data.size(); ++i) { + file << data[i]; + } + file.close(); + return true; + } + return false; +} + +std::ofstream* file_system::Open(const std::string& file_name, + std::ios_base::openmode mode) { + + + std::ofstream* file = new std::ofstream(); + file->open( file_name.c_str(),std::ios_base::binary | mode); + if (file->is_open()) { + + return file; + } + + return NULL; +} + +bool file_system::Write(std::ofstream* const file_stream, + const uint8_t* data, + uint32_t data_size) { + bool result = false; + if (file_stream) { + for (size_t i = 0; i < data_size; ++i) { + (*file_stream) << data[i]; + } + result = true; + } + return result; +} + +void file_system::Close(std::ofstream* file_stream) { + if (file_stream) { + file_stream->close(); + } +} + +std::string file_system::CurrentWorkingDirectory() { + size_t filename_max_lenght = 1024; + char currentAppPath[filename_max_lenght]; + memset(currentAppPath, 0, filename_max_lenght); + if (0 == getcwd(currentAppPath, filename_max_lenght)) { + LOG4CXX_WARN(logger_, "Could not get CWD"); + } + + char path[filename_max_lenght]; + memset(path, 0, filename_max_lenght); + snprintf(path, filename_max_lenght - 1, "%s", currentAppPath); + return std::string(path); +} + +bool file_system::DeleteFile(const std::string& name) { + if (FileExists(name) && IsAccessible(name, W_OK)) { + return !remove(name.c_str()); + } + return false; +} + +void file_system::remove_directory_content(const std::string& directory_name) { + int32_t return_code = 0; + DIR* directory = NULL; +#ifndef __QNXNTO__ + struct dirent dir_element_; + struct dirent* dir_element = &dir_element_; +#else + char* direntbuffer = + new char[offsetof(struct dirent, d_name) + + pathconf(directory_name.c_str(), _PC_NAME_MAX) + 1]; + struct dirent* dir_element = new(direntbuffer) dirent; +#endif + 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 { + remove(full_element_path.c_str()); + } + } + } + + closedir(directory); +#ifdef __QNXNTO__ + delete[] direntbuffer; +#endif +} + +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()); + } + return false; +} + +bool file_system::IsAccessible(const std::string& name, int32_t how) { + return !access(name.c_str(), how); +} + +bool file_system::IsWritingAllowed(const std::string& name) { + return IsAccessible(name, W_OK); +} + +bool file_system::IsReadingAllowed(const std::string& name) { + return IsAccessible(name, R_OK); +} + +std::vector<std::string> file_system::ListFiles( + const std::string& directory_name) { + std::vector<std::string> listFiles; + if (!DirectoryExists(directory_name)) { + return listFiles; + } + + int32_t return_code = 0; + DIR* directory = NULL; +#ifndef __QNXNTO__ + struct dirent dir_element_; + struct dirent* dir_element = &dir_element_; +#else + char* direntbuffer = + new char[offsetof(struct dirent, d_name) + + pathconf(directory_name.c_str(), _PC_NAME_MAX) + 1]; + struct dirent* dir_element = new(direntbuffer) dirent; +#endif + 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); +#ifdef __QNXNTO__ + delete[] direntbuffer; +#endif + } + + return listFiles; +} + +bool file_system::WriteBinaryFile(const std::string& name, + const std::vector<uint8_t>& contents) { + using namespace std; + ofstream output(name.c_str(), ios_base::binary|ios_base::trunc); + output.write(reinterpret_cast<const char*>(&contents.front()), + contents.size()); + return output.good(); +} + +bool file_system::ReadBinaryFile(const std::string& name, + std::vector<uint8_t>& result) { + if (!FileExists(name) || !IsAccessible(name, R_OK)) { + return false; + } + + std::ifstream file(name.c_str(), std::ios_base::binary); + std::ostringstream ss; + ss << file.rdbuf(); + const std::string& s = ss.str(); + + result.resize(s.length()); + std::copy(s.begin(), s.end(), result.begin()); + return true; +} + +bool file_system::ReadFile(const std::string& name, std::string& result) { + if (!FileExists(name) || !IsAccessible(name, R_OK)) { + return false; + } + + std::ifstream file(name.c_str()); + std::ostringstream ss; + ss << file.rdbuf(); + result = ss.str(); + return true; +} + +const std::string file_system::ConvertPathForURL(const std::string& path) { + std::string::const_iterator it_path = path.begin(); + std::string::const_iterator it_path_end = path.end(); + + const std::string reserved_symbols = "!#$&'()*+,:;=?@[] "; + std::string::const_iterator it_sym = reserved_symbols.begin(); + std::string::const_iterator it_sym_end = reserved_symbols.end(); + + std::string converted_path; + while (it_path != it_path_end) { + + it_sym = reserved_symbols.begin(); + for (; it_sym != it_sym_end; ++it_sym) { + + if (*it_path == *it_sym) { + size_t size = 100; + char percent_value[size]; + snprintf(percent_value, size, "%%%x", *it_path); + converted_path += percent_value; + ++it_path; + continue; + } + } + + converted_path += *it_path; + ++it_path; + } + + return converted_path; +} + +bool file_system::CreateFile(const std::string& path) { + std::ofstream file(path); + if (!(file.is_open())) { + return false; + } else { + file.close(); + return true; + } +} diff --git a/src/components/utils/src/lock_posix.cc b/src/components/utils/src/lock_posix.cc new file mode 100644 index 0000000000..7591d4b525 --- /dev/null +++ b/src/components/utils/src/lock_posix.cc @@ -0,0 +1,150 @@ +/** + * 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/lock.h" + +#include <errno.h> +#include <stdint.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 +{ + int32_t status = pthread_mutex_init(&mutex_, NULL); + if (status != 0) { + LOG4CXX_ERROR(logger_, "Failed to initialize mutex"); + } +} + +Lock::Lock(bool is_mutex_recursive) +#ifndef NDEBUG + : lock_taken_(0), + is_mutex_recursive_(is_mutex_recursive) +#endif // NDEBUG +{ + int32_t status; + + if (is_mutex_recursive) { + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + status = pthread_mutex_init(&mutex_, &attr); + } else { + status = pthread_mutex_init(&mutex_, NULL); + } + + if (status != 0) { + LOG4CXX_ERROR(logger_, "Failed to initialize mutex"); + } +} + +Lock::~Lock() { +#ifndef NDEBUG + if (lock_taken_ > 0) { + LOG4CXX_ERROR(logger_, "Destroying non-released mutex"); + } +#endif + int32_t status = pthread_mutex_destroy(&mutex_); + if (status != 0) { + LOG4CXX_ERROR(logger_, "Failed to destroy mutex"); + } +} + +void Lock::Acquire() { + int32_t status = pthread_mutex_lock(&mutex_); + if (status != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire mutex"); + } + 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"); + } + } + return ackquired; +} + +#ifndef NDEBUG +void Lock::AssertFreeAndMarkTaken() { + if ((lock_taken_ > 0) && !is_mutex_recursive_) { + LOG4CXX_ERROR(logger_, "Locking already taken not recurcive mutex"); + NOTREACHED(); + } + lock_taken_++; +} +void Lock::AssertTakenAndMarkFree() { + if (lock_taken_ == 0) { + LOG4CXX_ERROR(logger_, "Unlocking a mutex that is not taken"); + NOTREACHED(); + } + lock_taken_--; +} +#endif + + +} // 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 new file mode 100644 index 0000000000..1403a5f712 --- /dev/null +++ b/src/components/utils/src/log_message_loop_thread.cc @@ -0,0 +1,56 @@ +/* + * 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/log_message_loop_thread.h" +#include "utils/logger_status.h" + +namespace logger { + +void LogMessageHandler::Handle(const LogMessage message) { + message.logger->forcedLog(message.level, + message.entry, + message.timeStamp, + message.location, + message.threadName); +} + +LogMessageLoopThread::LogMessageLoopThread() : + LogMessageLoopThreadTemplate("Logger", new LogMessageHandler()) { +} + +LogMessageLoopThread::~LogMessageLoopThread() { +// we'll have to drop messages +// while deleting logger thread + logger_status = DeletingLoggerThread; +} + +} // namespace logger diff --git a/src/components/utils/src/logger_status.cc b/src/components/utils/src/logger_status.cc new file mode 100644 index 0000000000..be341b9add --- /dev/null +++ b/src/components/utils/src/logger_status.cc @@ -0,0 +1,39 @@ +/* + * 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_status.h" + +namespace logger { + +LoggerStatus logger_status = LoggerThreadNotCreated; + +} // namespace logger diff --git a/src/components/utils/src/push_log.cc b/src/components/utils/src/push_log.cc new file mode 100644 index 0000000000..49525a4f27 --- /dev/null +++ b/src/components/utils/src/push_log.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 "utils/push_log.h" +#include "utils/log_message_loop_thread.h" +#include "utils/logger_status.h" + +namespace logger { + +bool push_log(log4cxx::LoggerPtr logger, + log4cxx::LevelPtr level, + const std::string& entry, + log4cxx_time_t timeStamp, + const log4cxx::spi::LocationInfo& location, + const log4cxx::LogString& threadName + ) { + if (LoggerThreadCreated == logger_status) { + LogMessage message = {logger, level, entry, timeStamp, location, threadName}; + LogMessageLoopThread::instance()->PostMessage(message); + return true; + } + + if (LoggerThreadNotCreated == logger_status) { + logger_status = CreatingLoggerThread; +// we'll have to drop messages +// while creating logger thread + LogMessage message = {logger, level, entry, timeStamp, location, threadName}; + LogMessageLoopThread::instance()->PostMessage(message); + logger_status = LoggerThreadCreated; + return true; + } + +// also we drop messages +// while deleting logger thread + + return false; +} + +} // namespace logger diff --git a/src/components/utils/src/resource_usage.cc b/src/components/utils/src/resource_usage.cc new file mode 100644 index 0000000000..aaa9c1b4a7 --- /dev/null +++ b/src/components/utils/src/resource_usage.cc @@ -0,0 +1,192 @@ +#include "utils/resource_usage.h" +#if defined(__QNXNTO__) +#include <dirent.h> +#include <fcntl.h> +#include <pthread.h> +#include <sys/neutrino.h> +#include <sys/procfs.h> +#include <sys/stat.h> +#include <sys/trace.h> +#include <sys/types.h> +#include <unistd.h> +#endif +#include <sys/resource.h> +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <sstream> +#include "utils/file_system.h" + +namespace utils { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +const char* Resources::proc = "/proc/"; + +ResourseUsage* Resources::getCurrentResourseUsage() { + PidStats pid_stats; + if (false == GetProcInfo(pid_stats)) { + LOG4CXX_ERROR(logger_, "Failed to get cpu proc info"); + return NULL; + } + MemInfo mem_info; + if (false == GetMemInfo(mem_info)) { + LOG4CXX_ERROR(logger_, "Failed to get memory info"); + return NULL; + } + ResourseUsage* usage = new ResourseUsage(); + usage->utime = pid_stats.utime; + usage->stime = pid_stats.stime; + usage->memory = static_cast<long long int>(mem_info); + return usage; +} + +bool Resources::ReadStatFile(std::string& output) { + std::string filename = GetStatPath(); + if (false == file_system::FileExists(filename)) { + return false; + } + if (false == file_system::ReadFile(filename,output)) { + return false; + } + return true; +} + +bool Resources::GetProcInfo(Resources::PidStats& output) { +#if defined(OS_LINUX) + std::string proc_buf; + if (false == ReadStatFile(proc_buf)) { + return false; + } + uint32_t num_succes = sscanf(proc_buf.c_str(), + "%d" //pid + " %*s"//com + " %c" //state + " %d" //ppid + " %d" //pgrp + " %d" //session + " %d" //tty_nr + " %d" //tpgid + " %u" //flags + " %lu" //minflt + " %lu" //cminflt + " %lu" //majflt + " %lu" //cmajflt + " %lu" //utime + " %lu" //stime + " %ld" //cutime + " %ld" //cstime + " %ld" //priority + " %ld" //nice + " %ld" //num_threads + " %ld" //itrealvalue + " %llu" //starttime + " %lu" //vsize + " %ld" //rss + " %lu" //rsslim + " %lu" //startcode + " %lu" //endcode + " %lu" //startstack + " %lu" //kstkesp + " %lu" //kstkip + " %lu" //signal + " %lu" //blocked + " %lu" //sigignore + " %lu" //sigcatch + " %lu" //wchan + " %lu" //nswap + " %lu" //cnswap + " %d" //exit_signal + " %d" //processor + " %u" //rt_priority + " %u" //policy + " %llu" //delayacct_blkio_ticks + " %lu" //guest_time + " %ld" //cguest_time + ,&(output.pid), &(output.state), &(output.ppid), &(output.pgrp), &(output.session), + &(output.tty_nr), &(output.tpgid), &(output.flags), &(output.minflt), &(output.cminflt), + &(output.majflt), &(output.cmajflt), &(output.utime), &(output.stime), &(output.cutime), + &(output.cstime), &(output.priority), &( output.nice), &(output.num_threads), &(output.itrealvalue), + &(output.starttime), &(output.vsize), &(output.rss), &(output.rsslim), &(output.startcode), + &(output.endcode), &(output.startstack), &(output.kstkesp), &(output.kstkeip), &(output.signal), + &(output.blocked), &(output.sigignore), &(output.sigcatch), &(output.wchan), &(output.nswap), + &(output.cnswap), &(output.exit_signal), &(output.processor), &(output.rt_priority), &(output.policy), + &(output.delayacct_blkio_ticks), &(output.guest_time), &(output.cguest_time) + ); + if(num_succes != 43) { // 43 is number of iteams in Resources::PidStats + LOG4CXX_ERROR(logger_, "Couldn't parse all iteams in /proc/PID/stat file"); + return false; + } + return true; +#elif defined(__QNXNTO__) + int fd = open(GetProcPath().c_str(), O_RDONLY); + if (0 >= fd) { + LOG4CXX_ERROR(logger_, "Failed open process proc file : " << GetProcPath() << + "; error no : " << strerror( errno ) ); + return false; + } + devctl(fd, DCMD_PROC_INFO, &output, sizeof(output), 0); + close(fd); + return true; +#endif +} + +bool Resources::GetMemInfo(Resources::MemInfo &output) { + bool result = false; + #if defined(OS_LINUX) + Resources::PidStats pid_stat; + if (false == GetProcInfo(pid_stat)) { + LOG4CXX_ERROR(logger_, "Failed to get proc info"); + result = false; + } else { + output = pid_stat.vsize; + result = true; + } + +#elif defined(__QNXNTO__) + 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))) { + LOG4CXX_ERROR(logger_, "Unable to read : " << proc_dir); + result = false; + return result; + } + closedir(proc_dir); + if (-1 == stat(as_path.c_str(), &st) || 0 == st.st_size) { + LOG4CXX_ERROR(logger_, "Unable to stat : " << as_path.c_str()); + result = false; + return result; + } + output = st.st_size; + result = true; +#endif + return result; +} + +std::string Resources::GetStatPath() { + std::string filename; +#if defined(OS_LINUX) + filename = GetProcPath() + "/stat"; +#elif defined(__QNXNTO__) + filename = GetProcPath() + "/as"; +#endif + return filename; +} + +std::string Resources::GetProcPath() { + char buffer[1024]; + pid_t my_pid = getpid(); + snprintf(buffer, sizeof(buffer), "%s%d/", proc , my_pid); + std::string filename(buffer); + return filename; +} + +} // namespace utils diff --git a/src/components/utils/src/rwlock_posix.cc b/src/components/utils/src/rwlock_posix.cc new file mode 100644 index 0000000000..7cc850b25b --- /dev/null +++ b/src/components/utils/src/rwlock_posix.cc @@ -0,0 +1,70 @@ +/* + * 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/rwlock.h" +#include "utils/logger.h" + +namespace sync_primitives { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +RWLock::RWLock() { + if (pthread_rwlock_init(&rwlock_, 0) != 0) { + LOG4CXX_ERROR(logger_, "Failed to initialize rwlock"); + } +} + +RWLock::~RWLock() { + if (pthread_rwlock_destroy(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to destroy rwlock"); + } +} + +void RWLock::AcquireForReading() { + if (pthread_rwlock_rdlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for reading"); + } +} + +void RWLock::AcquireForWriting() { + if (pthread_rwlock_wrlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for writing"); + } +} + +void RWLock::Release() { + if (pthread_rwlock_unlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to release rwlock"); + } +} + +} // namespace sync_primitives diff --git a/src/components/utils/src/signals_linux.cc b/src/components/utils/src/signals_linux.cc new file mode 100644 index 0000000000..f592a1e22b --- /dev/null +++ b/src/components/utils/src/signals_linux.cc @@ -0,0 +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. +*/ +#include <csignal> +#include <stdint.h> + +namespace utils { + +bool SubscribeToTerminateSignal(void (*func)(int32_t p)) { + void (*prev_func)(int32_t p); + + prev_func = signal(SIGINT, func); + return (SIG_ERR != prev_func); +} + +bool ResetSubscribeToTerminateSignal() { + void (*prev_func)(int32_t p); + prev_func = signal(SIGINT, SIG_DFL); + return (SIG_ERR != prev_func); +} + +} // namespace utils diff --git a/src/components/utils/src/system.cc b/src/components/utils/src/system.cc new file mode 100644 index 0000000000..ee90315db0 --- /dev/null +++ b/src/components/utils/src/system.cc @@ -0,0 +1,167 @@ +/** + * 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. + */ +#ifdef __QNX__ +# include <process.h> +#else // __QNX__ +# include <sys/types.h> +# include <sys/wait.h> +# include <sys/stat.h> +# include <fcntl.h> +# include <unistd.h> +#endif // __QNX__ + +#include <algorithm> +#include <functional> +#include <cstring> + +#include "utils/logger.h" +#include "utils/system.h" + +namespace utils { + +CREATE_LOGGERPTR_LOCAL(logger_, "Utils") + +struct GetCString { + char * operator ()(const std::string& string) { + return const_cast<char*>(string.c_str()); + } +}; + +System::System(const std::string& command) + : command_(command) { + argv_.push_back(command); +} + +System::System(const std::string& file, const std::string& command) + : command_(file) { + argv_.push_back(command); +} + +bool System::Execute() { + return Execute(false); +} + +System& System::Add(const std::string& arg) { + argv_.push_back(arg); + return *this; +} + +#ifdef __QNX__ + +bool System::Execute(bool wait) { + size_t size = argv_.size(); + char * *argv = new char*[size + 1]; + std::transform(argv_.begin(), argv_.end(), argv, GetCString()); + argv[size] = NULL; + + int mode = wait ? P_WAIT : P_NOWAIT; + int ret = spawnvp(mode, command_.c_str(), argv); + delete[] argv; + + if (ret == -1) { + LOG4CXX_ERROR(logger_, "Can't execute command: " << command_ + << " Errno is: " << std::strerror(errno)); + return false; + } + + if (wait) { + return WEXITSTATUS(ret) == 0; + } + + return true; +} + +#else // __QNX__ + +bool System::Execute(bool wait) { + // Create a child process. + pid_t pid_command = fork(); + + switch (pid_command) { + case -1: { // Error + LOG4CXX_FATAL(logger_, "fork() failed!"); + return false; + } + case 0: { // Child process + int32_t fd_dev0 = open("/dev/null", O_RDWR, S_IWRITE); + if (0 > fd_dev0) { + LOG4CXX_FATAL(logger_, "Open dev0 failed!"); + return false; + } + // close input/output file descriptors. + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + // move input/output to /dev/null. + dup2(fd_dev0, STDIN_FILENO); + dup2(fd_dev0, STDOUT_FILENO); + dup2(fd_dev0, STDERR_FILENO); + + size_t size = argv_.size(); + char * *argv = new char*[size + 1]; + std::transform(argv_.begin(), argv_.end(), argv, GetCString()); + argv[size] = NULL; + + // Execute the program. + if (execvp(command_.c_str(), argv) == -1) { + LOG4CXX_ERROR(logger_, "Can't execute command: " << command_); + _exit(EXIT_FAILURE); + } + delete[] argv; + + return true; + } + default: { /* Parent process */ + LOG4CXX_INFO(logger_, "Process created with pid " << pid_command); + if (wait) { + int status; + pid_t wait_pid; + do { + wait_pid = waitpid(pid_command, &status, WUNTRACED | WCONTINUED); + if (wait_pid == -1) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Can't wait"); + _exit(EXIT_FAILURE); + return false; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + return WEXITSTATUS(status) == 0; + } + + return true; + } + } +} + +#endif // __QNX__ + +} // utils diff --git a/src/components/utils/src/threads/posix_thread.cc b/src/components/utils/src/threads/posix_thread.cc new file mode 100644 index 0000000000..faaadd673c --- /dev/null +++ b/src/components/utils/src/threads/posix_thread.cc @@ -0,0 +1,259 @@ +/* + * 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 <errno.h> + +#include <limits.h> +#include <stddef.h> +#include <signal.h> + +#include "utils/threads/thread.h" +#include "utils/threads/thread_manager.h" +#include "utils/logger.h" +#include "pthread.h" + +using namespace std; +using namespace threads::impl; + +namespace { + +static void* threadFunc(void* closure) { + threads::ThreadDelegate* delegate = + static_cast<threads::ThreadDelegate*>(closure); + delegate->threadMain(); + return NULL; +} + +static pthread_t main_thread_id; +static bool main_thread_id_set = false; + +#ifndef __QNXNTO__ + const int EOK = 0; +#endif + +#if defined(OS_POSIX) + const size_t THREAD_NAME_SIZE = 15; +#endif +} + +namespace threads { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +size_t Thread::kMinStackSize = PTHREAD_STACK_MIN; /* Ubuntu : 16384 ; QNX : 256; */ + +bool Thread::Id::operator==(const Thread::Id& other) const { + return pthread_equal(id_, other.id_) != 0; +} + +// static +Thread::Id Thread::CurrentId() { + return Id(pthread_self()); +} + +//static +std::string Thread::NameFromId(const Id& thread_id) { + return ThreadManager::instance()->GetName(thread_id.id_); +} + +//static +void Thread::SetNameForId(const Id& thread_id, const std::string& name) { + ThreadManager::instance()->RegisterName(thread_id.id_, name); + + const std::string striped_name = + name.length() > THREAD_NAME_SIZE ? std::string(name.begin(), name.begin() + THREAD_NAME_SIZE) : name; + + const int pthread_result = pthread_setname_np(thread_id.id_, striped_name.c_str()); + if (pthread_result != EOK) { + LOG4CXX_WARN(logger_,"Couldn't set pthread name \"" << striped_name + << "\", error code " << pthread_result << + " (" << strerror(pthread_result) << ")"); + } +} + +//static +void Thread::SetMainThread() { + main_thread_id = pthread_self(); + main_thread_id_set = true; +} + +//static +bool Thread::InterruptMainThread() { + if (!main_thread_id_set) { + LOG4CXX_WARN(logger_, "Cannot interrupt main thread: not specified"); + return false; + } + pthread_kill(main_thread_id, SIGINT); + return true; +} + +//static +void Thread::MaskSignals() { + sigset_t sigset; + sigfillset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, 0); +} + +//static +void Thread::UnmaskSignals() { + sigset_t sigset; + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, 0); +} + +Thread::Thread(const char* name, ThreadDelegate* delegate) + : name_(name ? name : "undefined"), + delegate_(delegate), + thread_handle_(0), + thread_options_(), + isThreadRunning_(false) { +} + +Thread::~Thread() { + ThreadManager::instance()->Unregister(thread_handle_); + delete delegate_; + LOG4CXX_INFO(logger_,"Deleted thread: " << name_); +} + +bool Thread::start() { + return startWithOptions(thread_options_); +} + +bool Thread::startWithOptions(const ThreadOptions& options) { + LOG4CXX_TRACE_ENTER(logger_); + if (!delegate_) { + NOTREACHED(); + LOG4CXX_ERROR(logger_, "NULL delegate"); + LOG4CXX_TRACE_EXIT(logger_); + return false; + } + + 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) << "\")"); + } + + 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) << "\")"); + } + } + + const size_t stack_size = thread_options_.stack_size(); + 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) << "\")"); + } + } + + pthread_result = pthread_create(&thread_handle_, &attributes, threadFunc, delegate_); + 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_); + } + LOG4CXX_TRACE_EXIT(logger_); + return isThreadRunning_; +} + +void Thread::stop() { + LOG4CXX_TRACE_ENTER(logger_); + LOG4CXX_DEBUG(logger_, "Canceling thread (#" << thread_handle_ + << " \"" << name_ << "\") from #" << pthread_self()); + if (!is_running()) { + LOG4CXX_WARN(logger_, "Thread (#" << thread_handle_ + << " \"" << name_ << "\") is not running"); + LOG4CXX_TRACE_EXIT(logger_); + return; + } + + // TODO (EZamakhov): why exitThreadMain return bool and stop does not? + if (delegate_ && !delegate_->exitThreadMain()) { + if (pthread_self() == thread_handle_) { + LOG4CXX_ERROR(logger_, + "Couldn't cancel the same thread (#" << thread_handle_ + << "\"" << name_ << "\")"); + } else { + 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) << "\")"); + } + } + } + + // Wait for the thread to exit. It should already have terminated but make + // sure this assumption is valid. + join(); + LOG4CXX_TRACE_EXIT(logger_); +} + +void Thread::join() { + LOG4CXX_TRACE_ENTER(logger_); + LOG4CXX_DEBUG(logger_, "Join thread (#" << thread_handle_ + << " \"" << name_ << "\") from #" << pthread_self()); + if (thread_handle_ == pthread_self()) { + LOG4CXX_ERROR(logger_, + "Couldn't join with the same thread (#" << thread_handle_ + << " \"" << name_ << "\")"); + } else { + const int pthread_result = pthread_join(thread_handle_, NULL); + if (pthread_result != EOK) { + LOG4CXX_WARN(logger_, + "Couldn't join thread (#" << thread_handle_ << " \"" << name_ << + "\") from thread #" << pthread_self() << ". Error code = " + << pthread_result << "(\"" << strerror(pthread_result) << "\")"); + } + } + isThreadRunning_ = false; + LOG4CXX_TRACE_EXIT(logger_); +} + +std::ostream& operator<<(std::ostream& os, const Thread::Id& thread_id) { + return os<<Thread::NameFromId(thread_id); +} + +} // namespace threads diff --git a/src/components/utils/src/threads/pulse_thread_delegate.cc b/src/components/utils/src/threads/pulse_thread_delegate.cc new file mode 100644 index 0000000000..8c580bea83 --- /dev/null +++ b/src/components/utils/src/threads/pulse_thread_delegate.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 <sys/netmgr.h> + +#include "utils/threads/pulse_thread_delegate.h" +#include "utils/logger.h" + +namespace threads { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +PulseThreadDelegate::PulseThreadDelegate() : run_(false) { + LOG4CXX_TRACE(logger_, "Creating QNX channel"); + chid_ = ChannelCreate(0); + if (chid_ == -1) { + LOG4CXX_ERROR(logger_, "Failed to create QNX channel"); + return; + } + LOG4CXX_DEBUG(logger_, "Created QNX channel " << chid_); + + LOG4CXX_TRACE(logger_, "Connecting to QNX channel " << chid_); + coid_ = ConnectAttach(ND_LOCAL_NODE, 0, chid_, _NTO_SIDE_CHANNEL, 0); + if (coid_ == -1) { + LOG4CXX_ERROR(logger_, "Failed to connect to QNX channel " << chid_); + return; + } + LOG4CXX_DEBUG(logger_, "Connected to QNX channel " << chid_); + + run_ = true; +} + +void PulseThreadDelegate::threadMain() { + if (!Init()) { + LOG4CXX_ERROR(logger_, "Failed to initialize thread for QNX channel " << chid_); + return; + } + while (run_) { + struct sigevent event; + SIGEV_PULSE_INIT(&event, coid_, SIGEV_PULSE_PRIO_INHERIT, PULSE_CODE, 0); + if (ArmEvent(&event)) { + struct _pulse pulse; + LOG4CXX_INFO(logger_, "Waiting for pulse on QNX channel " << chid_); + if (MsgReceivePulse(chid_, &pulse, sizeof(pulse), 0) != -1) { + LOG4CXX_INFO(logger_, "Received pulse on QNX channel " << chid_); + switch (pulse.code) { + case PULSE_CODE: + OnPulse(); + break; + } + } + else { + if (run_) { + LOG4CXX_WARN(logger_, "Error occurred while waiting for pulse on QNX channel " << chid_); + } + else { + LOG4CXX_INFO(logger_, "QNX channel " << chid_ << " is apparently destroyed"); + } + } + } + } + Finalize(); +} + +bool PulseThreadDelegate::exitThreadMain() { + run_ = false; + + LOG4CXX_TRACE(logger_, "Disconnecting from QNX channel " << chid_); + if (ConnectDetach(coid_) != -1) { + LOG4CXX_DEBUG(logger_, "Disconnected from QNX channel " << chid_); + } + else { + LOG4CXX_WARN(logger_, "Failed to disconnect from QNX channel " << chid_); + } + + LOG4CXX_TRACE(logger_, "Destroying QNX channel " << chid_); + if (ChannelDestroy(chid_) != -1) { // unblocks MsgReceivePulse() + LOG4CXX_DEBUG(logger_, "QNX channel " << chid_ << " destroyed"); + } + else { + LOG4CXX_WARN(logger_, "Failed to destroy QNX channel " << chid_); + } + + return true; +} + +} // namespace threads diff --git a/src/components/utils/src/threads/thread_manager.cc b/src/components/utils/src/threads/thread_manager.cc new file mode 100644 index 0000000000..32a073ad15 --- /dev/null +++ b/src/components/utils/src/threads/thread_manager.cc @@ -0,0 +1,115 @@ +/** + * 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/threads/thread_manager.h" +#include "utils/logger.h" + +#include <sstream> + +#if defined(OS_LINUX) +#include <sys/syscall.h> +#include <unistd.h> +#endif + +namespace threads { +namespace impl { +using namespace std; +using namespace sync_primitives; + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +namespace { + const char* kUnknownName = "UnnamedThread"; +} + +UnnamedThreadRegistry::UnnamedThreadRegistry() { +} + +UnnamedThreadRegistry::~UnnamedThreadRegistry() { +} + +std::string UnnamedThreadRegistry::GetUniqueName(PlatformThreadHandle id) { + AutoLock auto_lock(state_lock_); + IdNameMap::iterator found = id_number_.find(id); + if (found != id_number_.end()) { + return found->second; + } + ++last_thread_number_; + std::stringstream namestream; + namestream << kUnknownName << last_thread_number_; + return id_number_[id] = namestream.str(); +} + +ThreadManager::ThreadManager() { + names_.insert(kUnknownName); +} + +ThreadManager::~ThreadManager() { +} + +void ThreadManager::RegisterName(PlatformThreadHandle id, const string& name) { + AutoLock auto_lock(state_lock_); + if (names_.find(name) != names_.end()) { + LOG4CXX_ERROR(logger_, "Ignoring duplicate thread name: " << name); + return; + } + names_.insert(name); + pair<IdNamesMap::iterator, bool> inserted = + id_names_.insert(make_pair(id, name)); + if (!inserted.second) { + LOG4CXX_ERROR(logger_, "Trying to register thread name " << name + <<", but it is already registered with name " + <<inserted.first->second); + } +} + +string ThreadManager::GetName(PlatformThreadHandle id) const { + AutoLock auto_lock(state_lock_); + IdNamesMap::const_iterator found = id_names_.find(id); + if (found == id_names_.end()) { + LOG4CXX_WARN(logger_, "Thread " << id << " doesn't have associated name"); + return unnamed_thread_namer_.GetUniqueName(id); + } + return found->second; +} + +void ThreadManager::Unregister(PlatformThreadHandle id) { + AutoLock auto_lock(state_lock_); + IdNamesMap::iterator it = id_names_.find(id); + if(it != id_names_.end()) { + names_.erase(it->second); + id_names_.erase(it); + } +} + +} // namespace impl +} // namespace threads diff --git a/src/components/utils/src/threads/thread_validator.cc b/src/components/utils/src/threads/thread_validator.cc new file mode 100644 index 0000000000..5e9c88a7c9 --- /dev/null +++ b/src/components/utils/src/threads/thread_validator.cc @@ -0,0 +1,92 @@ +/** + * 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/threads/thread_validator.h" + +#include "utils/logger.h" +#include "utils/back_trace.h" + +namespace threads { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +SingleThreadSimpleValidator::SingleThreadSimpleValidator() + : creation_thread_id_(Thread::CurrentId()) { +} + +SingleThreadSimpleValidator::~SingleThreadSimpleValidator() { +} + +void SingleThreadSimpleValidator::AssertRunningOnCreationThread() const { + Thread::Id current_id = Thread::CurrentId(); + if (creation_thread_id_ != current_id) { + LOG4CXX_ERROR(logger_, "Single-threaded object created at thread " + << creation_thread_id_ + <<" is accessed from thread " + << current_id +#ifdef BACKTRACE_SUPPORT + << "\n" + << utils::Backtrace() +#endif + ); + } +} + + +SingleThreadValidator::SingleThreadValidator() + : owning_thread_id_(Thread::CurrentId()){ +} + +SingleThreadValidator::~SingleThreadValidator() { +} + +void SingleThreadValidator::PassToThread(Thread::Id thread_id) const { + owning_thread_id_ = thread_id; +} + +void SingleThreadValidator::AssertRunningOnValidThread() const { + Thread::Id current_id = Thread::CurrentId(); + if (owning_thread_id_ != current_id) { + LOG4CXX_ERROR(logger_, "Single-threaded object owned by thread " + << owning_thread_id_ + << " is accessed from thread " + << current_id << "\n" +#ifdef BACKTRACE_SUPPORT + << utils::Backtrace() +#endif + ); + } +} + + +} // namespace threads + +// vim: set ts=2 sw=2 et: diff --git a/src/components/utils/test/CMakeLists.txt b/src/components/utils/test/CMakeLists.txt new file mode 100644 index 0000000000..a9ed5acdac --- /dev/null +++ b/src/components/utils/test/CMakeLists.txt @@ -0,0 +1,17 @@ +include_directories ( + ${CMAKE_SOURCE_DIR}/src/3rd_party-static/gmock-1.7.0/include + ${CMAKE_SOURCE_DIR}/src/3rd_party-static/gmock-1.7.0/gtest/include) + +set(testSources + main.cc + file_system_test.cc + date_time_test.cc) + +set(testLibraries + gmock + gtest + Utils) + +add_executable(utils_test ${testSources}) +target_link_libraries(utils_test ${testLibraries}) + diff --git a/src/components/utils/test/date_time_test.cc b/src/components/utils/test/date_time_test.cc new file mode 100644 index 0000000000..ddcf679a16 --- /dev/null +++ b/src/components/utils/test/date_time_test.cc @@ -0,0 +1,128 @@ +/* +* 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/date_time.h" + +namespace test { +namespace components { +namespace utils { + +TEST(DateTimeTest, GetCurrentTime) { + const TimevalStruct time1 = date_time::DateTime::getCurrentTime(); + ASSERT_NE(0, time1.tv_sec); + ASSERT_GE(time1.tv_usec, 0); + + const TimevalStruct time2 = date_time::DateTime::getCurrentTime(); + ASSERT_NE(0, time2.tv_sec); + ASSERT_GE(time2.tv_usec, 0); + ASSERT_GE(time2.tv_sec, time1.tv_sec); +} + +TEST(DateTimeTest, GetmSecs) { + TimevalStruct time; + time.tv_sec = 1; + time.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + ASSERT_EQ(time.tv_sec * date_time::DateTime::MILLISECONDS_IN_SECOND + + time.tv_usec / date_time::DateTime::MICROSECONDS_IN_MILLISECONDS, + date_time::DateTime::getmSecs(time)); +} + +TEST(DateTimeTest, GetuSecs) { + TimevalStruct time; + time.tv_sec = 3; + time.tv_usec = 4; + + ASSERT_EQ(time.tv_sec * date_time::DateTime::MILLISECONDS_IN_SECOND * + date_time::DateTime::MICROSECONDS_IN_MILLISECONDS + time.tv_usec, + date_time::DateTime::getuSecs(time)); +} + +TEST(DateTimeTest, GetuSecsmSecs) { + TimevalStruct time; + time.tv_sec = 5; + time.tv_usec = 6; + + ASSERT_EQ( date_time::DateTime::getmSecs(time), + date_time::DateTime::getuSecs(time) / date_time::DateTime::MICROSECONDS_IN_MILLISECONDS); +} + +TEST(DateTimeTest, CalculateTimeSpan) { + const TimevalStruct time = date_time::DateTime::getCurrentTime(); + + const uint32_t sleep_time_mSec = 10; + usleep(sleep_time_mSec * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS); + + ASSERT_GE(date_time::DateTime::calculateTimeSpan(time), + sleep_time_mSec); +} + +TEST(DateTimeTest, CalculateTimeDiff) { + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + TimevalStruct time2; + time2.tv_sec = 3; + time2.tv_usec = 4 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + //time2 to time1 + TimevalStruct diff1; + diff1.tv_sec = time2.tv_sec - time1.tv_sec; + diff1.tv_usec = time2.tv_usec - time1.tv_usec; + + const int64_t mSecDiff = static_cast<int64_t>(diff1.tv_sec) * 1000 + + diff1.tv_usec / 1000; + + ASSERT_EQ(mSecDiff, + date_time::DateTime::calculateTimeDiff(time2, time1)); + + //time1 to time2 + TimevalStruct diff2; + diff2.tv_sec = time1.tv_sec - time2.tv_sec; + diff2.tv_usec = time1.tv_usec - time2.tv_usec; + + const int64_t mSecDiff2 = -(static_cast<int64_t>(diff2.tv_sec) * 1000 + + diff2.tv_usec / 1000); + + ASSERT_EQ(mSecDiff2, + date_time::DateTime::calculateTimeDiff(time1, time2)); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/file_system_test.cc b/src/components/utils/test/file_system_test.cc new file mode 100644 index 0000000000..abf09735ba --- /dev/null +++ b/src/components/utils/test/file_system_test.cc @@ -0,0 +1,111 @@ +/* + * 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 "gmock/gmock.h" +#include "utils/file_system.h" + +namespace test { +namespace components { +namespace utils { + +TEST(FileSystemTest, CommonFileSystemTest) { + // Directory creation + ASSERT_FALSE(file_system::DirectoryExists("./Test directory")); + + file_system::CreateDirectory("./Test directory"); + + ASSERT_TRUE(file_system::DirectoryExists("./Test directory")); + + ASSERT_TRUE(file_system::IsDirectory("./Test directory")); + + // File creation + ASSERT_FALSE(file_system::FileExists("./Test directory/test file")); + + std::vector<unsigned char> data; + data.push_back('t'); + data.push_back('e'); + data.push_back('s'); + data.push_back('t'); + + ASSERT_TRUE(file_system::Write("./Test directory/test file", data)); + + ASSERT_TRUE(file_system::FileExists("./Test directory/test file")); + + ASSERT_FALSE(file_system::IsDirectory("./Test directory/test file")); + + // Read data from file + std::vector<unsigned char> result; + + ASSERT_TRUE(file_system::ReadBinaryFile("./Test directory/test file", + result)); + ASSERT_FALSE(result.empty()); + + // list files + ASSERT_TRUE(file_system::Write("./Test directory/test file 2", data)); + + std::vector<std::string> list; + list = file_system::ListFiles("./Test directory"); + + ASSERT_FALSE(list.empty()); + std::sort(list.begin(), list.end()); + ASSERT_EQ("test file", list[0]); + ASSERT_EQ("test file 2", list[1]); + + // Delete file + ASSERT_TRUE(file_system::FileExists("./Test directory/test file 2")); + ASSERT_TRUE(file_system::DeleteFile("./Test directory/test file 2")); + ASSERT_FALSE(file_system::FileExists("./Test directory/test file 2")); + + // Delete empty directory + file_system::CreateDirectory("./Test directory/Empty directory"); + + ASSERT_TRUE(file_system::DirectoryExists( + "./Test directory/Empty directory")); + ASSERT_TRUE(file_system::RemoveDirectory( + "./Test directory/Empty directory", false)); + ASSERT_FALSE(file_system::DirectoryExists( + "./Test directory/Empty directory")); + + ASSERT_FALSE(file_system::RemoveDirectory("./Test directory", false)); + ASSERT_TRUE(file_system::DirectoryExists("./Test directory")); + + // Delete directory recursively + file_system::CreateDirectory("./Test directory/Test directory 2"); + ASSERT_TRUE(file_system::Write( + "./Test directory/Test directory 2/test file 2", data)); + ASSERT_TRUE(file_system::RemoveDirectory("./Test directory", true)); + + ASSERT_FALSE(file_system::DirectoryExists("./Test directory")); +} +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/main.cc b/src/components/utils/test/main.cc new file mode 100644 index 0000000000..d8242c89a0 --- /dev/null +++ b/src/components/utils/test/main.cc @@ -0,0 +1,7 @@ +#include "gmock/gmock.h" + +int main(int argc, char** argv) { + testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} + |