No more comments from me. Have not reviewed ..\tests files. Thanks, Ramesh.
On 3/23/2016 7:20 PM, Hans Nordebäck wrote: > Hi Anders, > > Minor comments below. /Thanks HansN > > -----Original Message----- > From: Anders Widell [mailto:[email protected]] > Sent: den 29 februari 2016 12:42 > To: [email protected] > Cc: [email protected] > Subject: [devel] [PATCH 1 of 1] base: Add C++ utility functions [#836] > > Makefile.common | 3 +- > configure.ac | 3 + > osaf/libs/core/Makefile.am | 7 +- > osaf/libs/core/cplusplus/Makefile.am | 21 + > osaf/libs/core/cplusplus/base/Makefile.am | 42 ++ > osaf/libs/core/cplusplus/base/getenv.cc | 160 ++++++++ > osaf/libs/core/cplusplus/base/getenv.h | 40 ++ > osaf/libs/core/cplusplus/base/macros.h | 33 + > osaf/libs/core/cplusplus/base/process.cc | 204 ++++++++++ > osaf/libs/core/cplusplus/base/process.h | 113 +++++ > osaf/libs/core/cplusplus/base/tests/Makefile.am | 49 ++ > osaf/libs/core/cplusplus/base/tests/getenv_test.cc | 105 +++++ > osaf/libs/core/cplusplus/base/tests/mock_logtrace.cc | 32 + > osaf/libs/core/cplusplus/base/tests/mock_logtrace.h | 23 + > osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.cc | 25 + > osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.h | 23 + > osaf/libs/core/cplusplus/base/tests/mock_osafassert.cc | 27 + > osaf/libs/core/cplusplus/base/tests/mock_osafassert.h | 23 + > osaf/libs/core/cplusplus/base/tests/time_add_test.cc | 54 ++ > osaf/libs/core/cplusplus/base/tests/time_compare_test.cc | 195 +++++++++ > osaf/libs/core/cplusplus/base/tests/time_convert_test.cc | 89 ++++ > osaf/libs/core/cplusplus/base/tests/time_subtract_test.cc | 52 ++ > osaf/libs/core/cplusplus/base/time.h | 275 > ++++++++++++++ > 23 files changed, 1594 insertions(+), 4 deletions(-) > > > Add the following C++ utility functions to the base component: > > * getenv.h - parsing of environment variables with default values > * macros.h - selecting behaviour of copy constructors and assignment operators > * process.h - time supervised execution of programs > * time.h - conversion to/from POSIX timespec structures > > diff --git a/Makefile.common b/Makefile.common > --- a/Makefile.common > +++ b/Makefile.common > @@ -6,7 +6,8 @@ CORE_INCLUDES = \ > -I$(top_srcdir)/osaf/libs/core/include \ > -I$(top_srcdir)/osaf/libs/core/leap/include \ > -I$(top_srcdir)/osaf/libs/core/mds/include \ > - -I$(top_srcdir)/osaf/libs/core/common/include > + -I$(top_srcdir)/osaf/libs/core/common/include \ > + -I$(top_srcdir)/osaf/libs/core/cplusplus > > AM_CPPFLAGS = \ > $(CORE_INCLUDES) \ > diff --git a/configure.ac b/configure.ac > --- a/configure.ac > +++ b/configure.ac > @@ -774,6 +774,9 @@ AC_CONFIG_FILES([ > osaf/libs/saf/libSaSmf/Makefile > osaf/libs/saf/libSaSmf/pkgconfig/Makefile > osaf/libs/saf/libSaSmf/pkgconfig/opensaf-smf.pc > + osaf/libs/core/cplusplus/Makefile > + osaf/libs/core/cplusplus/base/Makefile > + osaf/libs/core/cplusplus/base/tests/Makefile > osaf/services/Makefile > osaf/services/infrastructure/Makefile > osaf/services/infrastructure/dtms/Makefile > diff --git a/osaf/libs/core/Makefile.am b/osaf/libs/core/Makefile.am > --- a/osaf/libs/core/Makefile.am > +++ b/osaf/libs/core/Makefile.am > @@ -18,7 +18,7 @@ include $(top_srcdir)/Makefile.common > > MAINTAINERCLEANFILES = Makefile.in > > -SUBDIRS = include common leap mbcsv mds > +SUBDIRS = include common leap mbcsv mds cplusplus > > LIB_VERSION = 0:2:0 > > @@ -30,11 +30,12 @@ libopensaf_core_la_CPPFLAGS = \ > $(AM_CPPFLAGS) > > libopensaf_core_la_LDFLAGS = \ > - -lpthread -ldl -lrt \ > + -pthread -ldl -lrt -lstdc++ \ > -version-number $(LIB_VERSION) > > libopensaf_core_la_LIBADD = \ > $(top_builddir)/osaf/libs/core/common/libopensaf_common.la \ > $(top_builddir)/osaf/libs/core/leap/libleap.la \ > $(top_builddir)/osaf/libs/core/mbcsv/libmbca.la \ > - $(top_builddir)/osaf/libs/core/mds/libmds.la > + $(top_builddir)/osaf/libs/core/mds/libmds.la \ > + $(top_builddir)/osaf/libs/core/cplusplus/base/libbase.la > diff --git a/osaf/libs/core/cplusplus/Makefile.am > b/osaf/libs/core/cplusplus/Makefile.am > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/Makefile.am > @@ -0,0 +1,21 @@ > +# -*- OpenSAF -*- > +# > +# (C) Copyright 2016 The OpenSAF Foundation > +# > +# This program is distributed in the hope that it will be useful, but > +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +# or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > +# under the GNU Lesser General Public License Version 2.1, February 1999. > +# The complete license can be accessed from the following location: > +# http://opensource.org/licenses/lgpl-license.php > +# See the Copying file included with the OpenSAF distribution for full > +# licensing terms. > +# > +# Author(s): Ericsson AB > +# > + > +include $(top_srcdir)/Makefile.common > + > +MAINTAINERCLEANFILES = Makefile.in > + > +SUBDIRS = base > diff --git a/osaf/libs/core/cplusplus/base/Makefile.am > b/osaf/libs/core/cplusplus/base/Makefile.am > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/Makefile.am > @@ -0,0 +1,42 @@ > +# -*- OpenSAF -*- > +# > +# (C) Copyright 2016 The OpenSAF Foundation > +# > +# This program is distributed in the hope that it will be useful, but > +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +# or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > +# under the GNU Lesser General Public License Version 2.1, February 1999. > +# The complete license can be accessed from the following location: > +# http://opensource.org/licenses/lgpl-license.php > +# See the Copying file included with the OpenSAF distribution for full > +# licensing terms. > +# > +# Author(s): Ericsson AB > +# > + > +include $(top_srcdir)/Makefile.common > + > +MAINTAINERCLEANFILES = Makefile.in > + > +DEFAULT_INCLUDES = > + > +SUBDIRS = tests > + > +noinst_HEADERS = \ > + getenv.h \ > + macros.h \ > + process.h \ > + time.h > + > +noinst_LTLIBRARIES = libbase.la > + > +libbase_CXXFLAGS =$(AM_CXXFLAGS) > + > +libbase_la_CPPFLAGS = \ > + $(AM_CPPFLAGS) > + > +libbase_la_LDFLAGS = -static > + > +libbase_la_SOURCES = \ > + getenv.cc \ > + process.cc > diff --git a/osaf/libs/core/cplusplus/base/getenv.cc > b/osaf/libs/core/cplusplus/base/getenv.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/getenv.cc > @@ -0,0 +1,160 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef _GNU_SOURCE > +#define _GNU_SOURCE > +#endif > +#include "base/getenv.h" > > [HansN] from c++11 you can used #include <cstdint> > > +#include <stdint.h> > +#include <cerrno> > +#include <cstdlib> > +#include <cinttypes> > +#include <climits> > +#include <string> > +#include "logtrace.h" > + > +namespace { > + > +uint64_t GetEnvUnsigned(const char* environment_variable, > + uint64_t default_value, uint64_t max_value); > +int64_t GetEnvSigned(const char* environment_variable, > + int64_t default_value, int64_t max_value, > + int64_t min_value); > +char* RemoveLeadingWhitespace(char* str); > + > +} // namespace > + > +namespace base { > + > +template<> > +const char* GetEnv<const char*>(const char* environment_variable, > + const char* default_value) { > + const char* str = getenv(environment_variable); > + if (str == nullptr) { > + TRACE("%s is not set; using default value '%s'", environment_variable, > + default_value); > + str = default_value; > + } else { > + TRACE("%s = '%s'", environment_variable, str); > + } > + return str; > +} > + > +template<> > +std::string GetEnv<std::string>(const char* environment_variable, > + std::string default_value) { > + return GetEnv(environment_variable, default_value.c_str()); > +} > + > +template<> > +uint64_t GetEnv<uint64_t>(const char* environment_variable, > + uint64_t default_value) { > + return GetEnvUnsigned(environment_variable, default_value, UINT64_MAX); > +} > + > +template<> > +uint32_t GetEnv<uint32_t>(const char* environment_variable, > + uint32_t default_value) { > + return GetEnvUnsigned(environment_variable, default_value, UINT32_MAX); > +} > + > +template<> > +uint16_t GetEnv<uint16_t>(const char* environment_variable, > + uint16_t default_value) { > + return GetEnvUnsigned(environment_variable, default_value, UINT16_MAX); > +} > + > +template<> > +int64_t GetEnv<int64_t>(const char* environment_variable, > + int64_t default_value) { > + return GetEnvSigned(environment_variable, default_value, INT64_MAX, > + INT64_MIN); > +} > + > +template<> > +int32_t GetEnv<int32_t>(const char* environment_variable, > + int32_t default_value) { > + return GetEnvSigned(environment_variable, default_value, INT32_MAX, > + INT32_MIN); > +} > + > +template<> > +int16_t GetEnv<int16_t>(const char* environment_variable, > + int16_t default_value) { > + return GetEnvSigned(environment_variable, default_value, INT16_MAX, > + INT16_MIN); > +} > + > +} // namespace base > + > +namespace { > + > +uint64_t GetEnvUnsigned(const char* environment_variable, > + uint64_t default_value, uint64_t max_value) { > + char* str = RemoveLeadingWhitespace(getenv(environment_variable)); > + uint64_t retval = default_value; > + if (str != nullptr && *str != '\0') { > + errno = 0; > + char* endptr; > + unsigned long long val = strtoull(str, &endptr, 0); > + endptr = RemoveLeadingWhitespace(endptr); > + if (errno == 0 && val <= max_value && *endptr == '\0') { > + retval = val; > + TRACE("%s = %" PRIu64, environment_variable, retval); > + } else { > + LOG_ER("%s has invalid value '%s'; using default value %" PRIu64, > + environment_variable, str, default_value); > + } > + } else { > + TRACE("%s is %s; using default value %" PRIu64, environment_variable, > + str == nullptr ? "not set" : "empty", default_value); > + > + } > + return retval; > +} > + > +int64_t GetEnvSigned(const char* environment_variable, int64_t default_value, > + int64_t max_value, int64_t min_value) { > + char* str = RemoveLeadingWhitespace(getenv(environment_variable)); > + int64_t retval = default_value; > + if (str != nullptr && *str != '\0') { > + errno = 0; > + char* endptr; > + long long val = strtoll(str, &endptr, 0); > + endptr = RemoveLeadingWhitespace(endptr); > + if (errno == 0 && val >= min_value && val <= max_value && *endptr == > '\0') { > + retval = val; > + TRACE("%s = %" PRId64, environment_variable, retval); > + } else { > + LOG_ER("%s has invalid value '%s'; using default value %" PRId64, > + environment_variable, str, default_value); > + } > + } else { > + TRACE("%s is %s; using default value %" PRId64, environment_variable, > + str == nullptr ? "not set" : "empty", default_value); > + } > + return retval; > +} > + > +char* RemoveLeadingWhitespace(char* str) { > + if (str != nullptr) { > + while (*str == ' ' || *str == '\t' || *str == '\r' || *str == '\n') > ++str; > + } > + return str; > +} > + > +} // namespace > diff --git a/osaf/libs/core/cplusplus/base/getenv.h > b/osaf/libs/core/cplusplus/base/getenv.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/getenv.h > @@ -0,0 +1,40 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_GETENV_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_GETENV_H_ > + > +namespace base { > + > +/** > + * @brief Parse an environment variable with a default value. > + * > + * Returns the contents of an environment variable. If the variable is not > set > + * or not possible to parse, the @a default_value will be returned. This is a > + * template functions, and the return type will be the same as the type of > the > + * @a default_value. Supported types are strings (const char*, std::string), > as > + * well as signed and unsigned integer types. When parsing integers, the > + * prefixes 0x and 0 are supported for indicating that the number is > hexadecimal > + * or octal, respectively. The parsed value is always logged using the > OpenSAF > + * logtrace functionality, and parse errors are logged to syslog. > + */ > +template<typename T> > +T GetEnv(const char* environment_variable, T default_value); > + > +} // namespace base > + > +#endif /* OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_GETENV_H_ */ > diff --git a/osaf/libs/core/cplusplus/base/macros.h > b/osaf/libs/core/cplusplus/base/macros.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/macros.h > @@ -0,0 +1,33 @@ > +/* > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_MACROS_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_MACROS_H_ > + > +#define USE_DEFAULT_COPY_AND_MOVE_OPERATORS(className) \ > + className(className&&) = default; \ > + className(const className&) = default; \ > + className& operator=(className&&) = default; \ > + className& operator=(const className&) = default > + > +#define DELETE_COPY_AND_MOVE_OPERATORS(className) \ > + className(className&&) = delete; \ > + className(const className&) = delete; \ > + className& operator=(className&&) = delete; \ > + className& operator=(const className&) = delete > + > +#endif /* OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_MACROS_H_ */ > diff --git a/osaf/libs/core/cplusplus/base/process.cc > b/osaf/libs/core/cplusplus/base/process.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/process.cc > @@ -0,0 +1,204 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef _GNU_SOURCE > +#define _GNU_SOURCE > +#endif > +#include "base/process.h" > +#include <sys/resource.h> > +#include <sys/wait.h> > +#include <unistd.h> > +#include <cerrno> > +#include <cinttypes> > +#include <climits> > +#include <cstdlib> > +#include <cstring> > +#include <thread> > +#include "logtrace.h" > +#include "base/time.h" > + > +namespace { > [HansN] the static in unnamed namespaces is not necessary > +static char path_environment_variable[] = "PATH=/usr/local/sbin:" \ > + "/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; > +} > + > +namespace base { > + > +Process::Process() : > + mutex_{}, > + timer_id_{}, > + is_timer_created_{false}, > + process_group_id_{0} { > +} > + > +Process::~Process() { > + StopTimer(); > +} > + > +void Process::Kill(int sig_no, const Duration& wait_time) { > + std::unique_lock<std::mutex> lock(mutex_); > [HansN] could be made lock free if using std::atomic instead, e.g. > std::atomic<pid_t> process_group_id_ {1234}; > pid_t pgid {0}; > pgid = process_group_id_.exchange(pgid); > > + pid_t pgid = process_group_id_; > + process_group_id_ = 0; > + lock.unlock(); > + if (pgid > 1) KillProc(-pgid, sig_no, wait_time); > +} > + > +void Process::KillProc(pid_t pid, int sig_no, const Duration& wait_time) { > + LOG_NO("Sending signal %d to PID %d", sig_no, (int) pid); > + if (kill(pid, sig_no) == 0) { > + TimePoint timeout = Clock::now() + wait_time; > + for (;;) { > + int status; > + pid_t wait_pid = waitpid(pid, &status, WNOHANG); > + if (wait_pid == (pid_t) -1) { > + if (errno == ECHILD) break; > + if (errno != EINTR) osaf_abort(pid); > + } > + if (Clock::now() >= timeout) { > + if (sig_no == SIGTERM) { > + KillProc(pid, SIGKILL, wait_time); > + } else { > + LOG_WA("Failed to kill %d", (int) pid); > + } > + break; > + } > + if (wait_pid == 0) { > + std::this_thread::sleep_for(std::chrono::milliseconds(10)); > + } > + } > + } else if (errno == EPERM) { > + LOG_WA("kill(%d, %d) failed due to EPERM", (int) pid, sig_no); > + } else if (errno != ESRCH) { > + osaf_abort(pid); > + } > +} > + > +void Process::Execute(int argc, char *argv[], const Duration& timeout) { > + struct rlimit rlim; > + int nofile = 1024; > + char *const env[] = { path_environment_variable, nullptr }; > + > + TRACE_ENTER(); > + osafassert(argc >= 1 && argv[argc] == nullptr); > + LOG_NO("Running '%s' with %d argument(s)", argv[0], argc - 1); > + > + if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { > + if (rlim.rlim_cur != RLIM_INFINITY && > + rlim.rlim_cur <= INT_MAX && (int) rlim.rlim_cur >= 0) { > + nofile = rlim.rlim_cur; > + } else { > + LOG_ER("RLIMIT_NOFILE is out of bounds: %llu", > + (unsigned long long) rlim.rlim_cur); > + } > + } else { > + LOG_ER("getrlimit(RLIMIT_NOFILE) failed: %s", strerror(errno)); > + } > + > + pid_t child_pid = fork(); > + if (child_pid == 0) { > + setpgid(0, 0); > + for (int fd = 3; fd < nofile; ++fd) close(fd); > + execve(argv[0], argv, env); > + _Exit(123); > + } else if (child_pid != (pid_t) -1 && child_pid != 1) { > + if (setpgid(child_pid, 0) != 0) { > + LOG_WA("setpgid(%u, 0) failed: %s", > + (unsigned) child_pid, strerror(errno)); > + } > + std::unique_lock<std::mutex> lock(mutex_); > [HansN] see comment above, std::atomic > + process_group_id_ = child_pid; > + StartTimer(timeout); > + lock.unlock(); > + int status; > + pid_t wait_pid; > + do { > + wait_pid = waitpid(child_pid, &status, 0); > + } while (wait_pid == (pid_t) -1 && errno == EINTR); > + lock.lock(); > + StopTimer(); > + bool killed = process_group_id_ == 0; > + process_group_id_ = 0; > + lock.unlock(); > + bool successful = false; > + if (!killed && wait_pid != (pid_t) -1) { > + if (!WIFEXITED(status)) { > + LOG_ER("'%s' terminated abnormally", argv[0]); > + } else if (WEXITSTATUS(status) != 0) { > + if (WEXITSTATUS(status) == 123) { > + LOG_ER("'%s' could not be executed", argv[0]); > + } else { > + LOG_ER("'%s' failed with exit code %d", argv[0], > + WEXITSTATUS(status)); > + } > + } else { > + LOG_IN("'%s' exited successfully", argv[0]); > + successful = true; > + } > + } else if (!killed) { > + LOG_ER("'%s' failed in waitpid(%u): %s", > + argv[0], (unsigned) child_pid, strerror(errno)); > + } > + if (!successful) KillProc(-child_pid, SIGTERM, std::chrono::seconds(2)); > + } else { > + LOG_ER("'%s' failed in fork(): %s", argv[0], > + strerror(errno)); > + } > + TRACE_LEAVE(); > +} > + > +void Process::StartTimer(const Duration& timeout) { > + if (timeout != std::chrono::seconds(0)) { > + if (!is_timer_created_) { > + sigevent event; > + event.sigev_notify = SIGEV_THREAD; > + event.sigev_value.sival_ptr = this; > + event.sigev_notify_function = TimerExpirationEvent; > + event.sigev_notify_attributes = nullptr; > + int result; > + do { > + result = timer_create(CLOCK_MONOTONIC, &event, &timer_id_); > + if (result == -1 && errno == EAGAIN) { > + std::this_thread::sleep_for(std::chrono::milliseconds(10)); > + } > + } while (result == -1 && errno == EAGAIN); > + if (result != 0) osaf_abort(result); > + is_timer_created_ = true; > + } > + itimerspec tmrspec; > + tmrspec.it_interval = kZeroSeconds; > + tmrspec.it_value = DurationToTimespec(timeout); > + if (timer_settime(timer_id_, 0, &tmrspec, nullptr) != 0) osaf_abort(0); > + } else { > + StopTimer(); > + } > +} > + > +void Process::StopTimer() { > + if (is_timer_created_) { > + if (timer_delete(timer_id_) != 0) osaf_abort(0); > + is_timer_created_ = false; > + } > +} > + > +void Process::TimerExpirationEvent(sigval notification_data) { > + LOG_ER("Process execution timed out; sending SIGTERM to the process > group"); > + Process* instance = static_cast<Process*>(notification_data.sival_ptr); > + instance->Kill(SIGTERM, std::chrono::seconds(2)); > +} > + > +} // namespace base > + > diff --git a/osaf/libs/core/cplusplus/base/process.h > b/osaf/libs/core/cplusplus/base/process.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/process.h > @@ -0,0 +1,113 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_PROCESS_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_PROCESS_H_ > + > +#include <csignal> > [HansN] use #include <cstdint> > +#include <stdint.h> > +#include <ctime> > +#include <chrono> > +#include <mutex> > +#include "base/macros.h" > + > +namespace base { > + > +class Process { > + DELETE_COPY_AND_MOVE_OPERATORS(Process); > + public: > + using Duration = std::chrono::steady_clock::duration; > + Process(); > + virtual ~Process(); > + /** > + * @brief Execute a program with a timeout. > + * > + * Execute a program in a new process group, with the parameters specified > in > + * @a argc and @a argv (analogous to the parameters taken by the main() > + * function). The first index in argv must be the full path to the > executable > + * file. The rest of the parameters shall specify the arguments to the > + * program. In addition, argv[argc] must be a NULL pointer. This function > + * blocks until the called program has exited or until the @a timeout > expires, > + * whichever happens first. If the @a timeout expires, all the processes in > + * the new process group of the started program will be killed by calling > the > + * Kill() method of this class with the SIGTERM signal. A @a timeout of > zero > + * will give an infinite timeout. > + * > + * The program will be executed with an empty environment containing just a > + * PATH variable with the fixed value set to the following string: > + * /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin > + * > + * You should not try to execute several programs concurrently using the > same > + * instance of this class, since the timeout handling only supports waiting > + * for one program at a time. > + */ > + void Execute(int argc, char *argv[], const Duration& timeout); > + /** > + * @brief Check if there is currently an executing process. > + * > + * Returns true if there is currently an executing process that was started > + * using this instance of the Process class. Note that if the process(es) > are > + * currently being killed (i.e. because of a call to the Kill() method or > + * because the timeout has expired), this method may return false even > though > + * not all processes have yet been killed. > + */ > + bool is_executing() const { > + return process_group_id_ > 1; > + } > + /** > + * @brief Kill the currently executing program. > + * > + * This function kills the currently executing program by calling the > + * KillProc() method on the new process group that was created when > starting > + * the program. > + */ > + void Kill(int sig_no, const Duration& wait_time); > + /** > + * @brief Send a signal to a process (group) and wait for it to terminate. > + * > + * This is a utility function that works in a similar way as the > killproc(8) > + * command. It sends the signal @a sig_no to the process @a pid, and waits > for > + * @a wait_time or until the process has terminated, whichever happens > + * first. If @a sig_no is SIGTERM and the process does not terminate before > + * the @a wait_time have passed, this function will retry by sending > SIGKILL > + * to @a pid and again waiting @a wait_time for it to terminate. In the > worst > + * case, the total wait time can thus be two times @a wait_time when @a > sig_no > + * is SIGTERM; however, in practice the process will terminate very quickly > + * after receiving SIGKILL since this signal cannot be caught, and the the > + * total wait time should thus not be much longer than @a wait_time. > + * > + * It is also possible to use this function to send a signal to a process > + * group, by passing a negative value as @a pid (in a similar way as with > the > + * kill(2) function). In that case, this function will wait until all > + * processes in the process group have terminated. > + */ > + static void KillProc(pid_t pid, int sig_no, const Duration& wait_time); > + private: > + using Clock = std::chrono::steady_clock; > + using TimePoint = std::chrono::steady_clock::time_point; > + void StartTimer(const Duration& timeout); > + void StopTimer(); > + static void TimerExpirationEvent(sigval notification_data); > + std::mutex mutex_; > + timer_t timer_id_; > + bool is_timer_created_; > + pid_t process_group_id_; > +}; > + > +} // namespace base > + > +#endif /* OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_PROCESS_H_ */ > diff --git a/osaf/libs/core/cplusplus/base/tests/Makefile.am > b/osaf/libs/core/cplusplus/base/tests/Makefile.am > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/Makefile.am > @@ -0,0 +1,49 @@ > +# -*- OpenSAF -*- > +# > +# (C) Copyright 2016 The OpenSAF Foundation > +# > +# This program is distributed in the hope that it will be useful, but > +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +# or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > +# under the GNU Lesser General Public License Version 2.1, February 1999. > +# The complete license can be accessed from the following location: > +# http://opensource.org/licenses/lgpl-license.php > +# See the Copying file included with the OpenSAF distribution for full > +# licensing terms. > +# > +# Author(s): Ericsson AB > +# > + > +include $(top_srcdir)/Makefile.common > + > +MAINTAINERCLEANFILES = Makefile.in > + > +TESTS = libbase_test > + > +check_PROGRAMS = $(TESTS) > + > +libbase_test_CXXFLAGS =$(AM_CXXFLAGS) > + > +libbase_test_CPPFLAGS = \ > + $(AM_CPPFLAGS) \ > + -I$(top_srcdir)/osaf/libs/core/cplusplus \ > + -I$(GTEST_DIR)/include > + > +libbase_test_LDFLAGS = \ > + -pthread -lrt \ > + $(top_builddir)/osaf/libs/core/cplusplus/base/libbase_la-getenv.o \ > + $(top_builddir)/osaf/libs/core/cplusplus/base/libbase_la-process.o > + > +libbase_test_SOURCES = \ > + time_add_test.cc \ > + time_subtract_test.cc \ > + time_compare_test.cc \ > + time_convert_test.cc \ > + getenv_test.cc \ > + mock_logtrace.cc \ > + mock_osafassert.cc \ > + mock_osaf_abort.cc > + > +libbase_test_LDADD = \ > + $(GTEST_DIR)/lib/libgtest.la \ > + $(GTEST_DIR)/lib/libgtest_main.la > diff --git a/osaf/libs/core/cplusplus/base/tests/getenv_test.cc > b/osaf/libs/core/cplusplus/base/tests/getenv_test.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/getenv_test.cc > @@ -0,0 +1,105 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include <cstdlib> > +#include <cstring> > +#include "base/getenv.h" > +#include "gtest/gtest.h" > + > +TEST(BaseGetEnv, StringDefault) { > + unsetenv("HELLO"); > + std::string default_value{"DEFAULT_VALUE"}; > + std::string value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, default_value); > +} > + > +TEST(BaseGetEnv, StringValue) { > + setenv("HELLO", "THERE", 1); > + std::string default_value{"DEFAULT_VALUE"}; > + std::string value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, std::string{"THERE"}); > +} > + > +TEST(BaseGetEnv, CharDefault) { > + unsetenv("HELLO"); > + const char* default_value{"DEFAULT_VALUE"}; > + const char* value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(strcmp(value, default_value), 0); > +} > + > +TEST(BaseGetEnv, CharValue) { > + setenv("HELLO", "THERE", 1); > + const char* default_value{"DEFAULT_VALUE"}; > + const char* value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(strcmp(value, "THERE"), 0); > +} > + > +TEST(BaseGetEnv, NegativeSignedIntegerDefault) { > + unsetenv("HELLO"); > + int64_t default_value{-1234567890123456789ll}; > + int64_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, default_value); > +} > + > +TEST(BaseGetEnv, NegativeSignedIntegerValue) { > + setenv("HELLO", "-2345678901234567890", 1); > + int64_t default_value{-1234567890123456789ll}; > + int64_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, -2345678901234567890ll); > +} > + > +TEST(BaseGetEnv, PositiveSignedIntegerDefault) { > + unsetenv("HELLO"); > + int64_t default_value{1234567890123456789ll}; > + int64_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, default_value); > +} > + > +TEST(BaseGetEnv, PositiveSignedIntegerValue) { > + setenv("HELLO", "2345678901234567890", 1); > + int64_t default_value{1234567890123456789ll}; > + int64_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, 2345678901234567890ll); > +} > + > +TEST(BaseGetEnv, HexadecimalUnsignedIntegerDefault) { > + unsetenv("HELLO"); > + uint64_t default_value{0xfefefefefefefefeull}; > + uint64_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, default_value); > +} > + > +TEST(BaseGetEnv, HexadecimalUnsignedIntegerValue) { > + setenv("HELLO", "0xabababababababab", 1); > + uint64_t default_value{0xfefefefefefefefeull}; > + uint64_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, 0xababababababababull); > +} > + > +TEST(BaseGetEnv, UnparsableInteger) { > + setenv("HELLO", "THERE", 1); > + uint32_t default_value{0xfefefefeul}; > + uint32_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, default_value); > +} > + > +TEST(BaseGetEnv, IntegerWithTrailingGarbage) { > + setenv("HELLO", "12ab", 1); > + uint32_t default_value{0xcdcdcdcdul}; > + uint32_t value = base::GetEnv("HELLO", default_value); > + EXPECT_EQ(value, default_value); > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/mock_logtrace.cc > b/osaf/libs/core/cplusplus/base/tests/mock_logtrace.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/mock_logtrace.cc > @@ -0,0 +1,32 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "mock_logtrace.h" > + > +void _logtrace_log(const char *file, unsigned int line, int priority, const > char *format, ...) { > + (void) file; > + (void) line; > + (void) priority; > + (void) format; > +} > + > +void _logtrace_trace(const char *file, unsigned int line, unsigned int > category, const char *format, ...) { > + (void) file; > + (void) line; > + (void) category; > + (void) format; > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/mock_logtrace.h > b/osaf/libs/core/cplusplus/base/tests/mock_logtrace.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/mock_logtrace.h > @@ -0,0 +1,23 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TESTS_MOCK_LOGTRACE_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TESTS_MOCK_LOGTRACE_H_ > + > +#include "logtrace.h" > + > +#endif > diff --git a/osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.cc > b/osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.cc > @@ -0,0 +1,25 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "mock_osaf_abort.h" > +#include <cstdlib> > + > +void osaf_abort(long i_cause) > +{ > + (void) i_cause; > + abort(); > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.h > b/osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/mock_osaf_abort.h > @@ -0,0 +1,23 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TESTS_MOCK_OSAF_ABORT_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TESTS_MOCK_OSAF_ABORT_H_ > + > +#include "osaf_utility.h" > + > +#endif > diff --git a/osaf/libs/core/cplusplus/base/tests/mock_osafassert.cc > b/osaf/libs/core/cplusplus/base/tests/mock_osafassert.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/mock_osafassert.cc > @@ -0,0 +1,27 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "mock_osafassert.h" > +#include <cstdlib> > + > +void __osafassert_fail(const char *file, int line, const char* func, const > char *assertion) { > + (void) file; > + (void) line; > + (void) func; > + (void) assertion; > + abort(); > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/mock_osafassert.h > b/osaf/libs/core/cplusplus/base/tests/mock_osafassert.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/mock_osafassert.h > @@ -0,0 +1,23 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TESTS_MOCK_OSAFASSERT_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TESTS_MOCK_OSAFASSERT_H_ > + > +#include "ncsgl_defs.h" > + > +#endif > diff --git a/osaf/libs/core/cplusplus/base/tests/time_add_test.cc > b/osaf/libs/core/cplusplus/base/tests/time_add_test.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/time_add_test.cc > @@ -0,0 +1,54 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "base/time.h" > +#include "gtest/gtest.h" > + > +static const timespec kTwoDotFourSeconds = { 2, 400000000 }; > +static const timespec kFourDotEightSeconds = { 4, 800000000 }; > +static const timespec kNineDotSixSeconds = { 9, 600000000 }; > +static const timespec number1 = { 576315623, 358743382 }; > +static const timespec number2 = { 1279394477, 719128783 }; > +static const timespec sum = { 1855710101, 77872165 }; > + > +TEST(BaseTimeAdd, ZeroPlusZero) { > + timespec result = base::kZeroSeconds + base::kZeroSeconds; > + EXPECT_TRUE(result == base::kZeroSeconds); > +} > + > +TEST(BaseTimeAdd, TwoDotFourAddedWithItself) { > + timespec result = kTwoDotFourSeconds; > + result += result; > + EXPECT_TRUE(result == kFourDotEightSeconds); > +} > + > +TEST(BaseTimeAdd, FourDotEightAddedWithItself) { > + timespec result = kFourDotEightSeconds; > + result += result; > + EXPECT_TRUE(result == kNineDotSixSeconds); > +} > + > +TEST(BaseTimeAdd, AddRandomNumbers) { > + timespec result = number1 + number2; > + EXPECT_TRUE(result == sum); > +} > + > +TEST(BaseTimeAdd, FirstParameterAndResultAtSameAddress) { > + timespec result = number1; > + result += number2; > + EXPECT_TRUE(result == sum); > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/time_compare_test.cc > b/osaf/libs/core/cplusplus/base/tests/time_compare_test.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/time_compare_test.cc > @@ -0,0 +1,195 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "base/time.h" > +#include "gtest/gtest.h" > + > +static const timespec kZeroDotNineSeconds = { 0, 900000000 }; > +static const timespec kOneDotOneSeconds = { 1, 100000000 }; > + > +TEST(BaseTimeCompare, ZeroWithZero) { > + EXPECT_FALSE(base::kZeroSeconds < base::kZeroSeconds); > + EXPECT_TRUE(base::kZeroSeconds <= base::kZeroSeconds); > + EXPECT_TRUE(base::kZeroSeconds == base::kZeroSeconds); > + EXPECT_FALSE(base::kZeroSeconds != base::kZeroSeconds); > + EXPECT_TRUE(base::kZeroSeconds >= base::kZeroSeconds); > + EXPECT_FALSE(base::kZeroSeconds > base::kZeroSeconds); > +} > + > +TEST(BaseTimeCompare, ZeroWithZeroDotOne) { > + EXPECT_TRUE(base::kZeroSeconds < base::kOneHundredMilliseconds); > + EXPECT_TRUE(base::kZeroSeconds <= base::kOneHundredMilliseconds); > + EXPECT_FALSE(base::kZeroSeconds == base::kOneHundredMilliseconds); > + EXPECT_TRUE(base::kZeroSeconds != base::kOneHundredMilliseconds); > + EXPECT_FALSE(base::kZeroSeconds >= base::kOneHundredMilliseconds); > + EXPECT_FALSE(base::kZeroSeconds > base::kOneHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, ZeroDotOneWithZero) { > + EXPECT_FALSE(base::kOneHundredMilliseconds < base::kZeroSeconds); > + EXPECT_FALSE(base::kOneHundredMilliseconds <= base::kZeroSeconds); > + EXPECT_FALSE(base::kOneHundredMilliseconds == base::kZeroSeconds); > + EXPECT_TRUE(base::kOneHundredMilliseconds != base::kZeroSeconds); > + EXPECT_TRUE(base::kOneHundredMilliseconds >= base::kZeroSeconds); > + EXPECT_TRUE(base::kOneHundredMilliseconds > base::kZeroSeconds); > +} > + > +TEST(BaseTimeCompare, ZeroWithOne) { > + EXPECT_TRUE(base::kZeroSeconds < base::kOneSecond); > + EXPECT_TRUE(base::kZeroSeconds <= base::kOneSecond); > + EXPECT_FALSE(base::kZeroSeconds == base::kOneSecond); > + EXPECT_TRUE(base::kZeroSeconds != base::kOneSecond); > + EXPECT_FALSE(base::kZeroSeconds >= base::kOneSecond); > + EXPECT_FALSE(base::kZeroSeconds > base::kOneSecond); > +} > + > +TEST(BaseTimeCompare, OneWithZero) { > + EXPECT_FALSE(base::kOneSecond < base::kZeroSeconds); > + EXPECT_FALSE(base::kOneSecond <= base::kZeroSeconds); > + EXPECT_FALSE(base::kOneSecond == base::kZeroSeconds); > + EXPECT_TRUE(base::kOneSecond != base::kZeroSeconds); > + EXPECT_TRUE(base::kOneSecond >= base::kZeroSeconds); > + EXPECT_TRUE(base::kOneSecond > base::kZeroSeconds); > +} > + > +TEST(BaseTimeCompare, OneWithOne) { > + EXPECT_FALSE(base::kOneSecond < base::kOneSecond); > + EXPECT_TRUE(base::kOneSecond <= base::kOneSecond); > + EXPECT_TRUE(base::kOneSecond == base::kOneSecond); > + EXPECT_FALSE(base::kOneSecond != base::kOneSecond); > + EXPECT_TRUE(base::kOneSecond >= base::kOneSecond); > + EXPECT_FALSE(base::kOneSecond > base::kOneSecond); > +} > + > +TEST(BaseTimeCompare, OneWithOneDotOne) { > + EXPECT_TRUE(base::kOneSecond < kOneDotOneSeconds); > + EXPECT_TRUE(base::kOneSecond <= kOneDotOneSeconds); > + EXPECT_FALSE(base::kOneSecond == kOneDotOneSeconds); > + EXPECT_TRUE(base::kOneSecond != kOneDotOneSeconds); > + EXPECT_FALSE(base::kOneSecond >= kOneDotOneSeconds); > + EXPECT_FALSE(base::kOneSecond > kOneDotOneSeconds); > +} > + > +TEST(BaseTimeCompare, OneDotOneWithOne) { > + EXPECT_FALSE(kOneDotOneSeconds < base::kOneSecond); > + EXPECT_FALSE(kOneDotOneSeconds <= base::kOneSecond); > + EXPECT_FALSE(kOneDotOneSeconds == base::kOneSecond); > + EXPECT_TRUE(kOneDotOneSeconds != base::kOneSecond); > + EXPECT_TRUE(kOneDotOneSeconds >= base::kOneSecond); > + EXPECT_TRUE(kOneDotOneSeconds > base::kOneSecond); > +} > + > +TEST(BaseTimeCompare, ZeroDotNineWithZeroDotNine) { > + EXPECT_FALSE(kZeroDotNineSeconds < kZeroDotNineSeconds); > + EXPECT_TRUE(kZeroDotNineSeconds <= kZeroDotNineSeconds); > + EXPECT_TRUE(kZeroDotNineSeconds == kZeroDotNineSeconds); > + EXPECT_FALSE(kZeroDotNineSeconds != kZeroDotNineSeconds); > + EXPECT_TRUE(kZeroDotNineSeconds >= kZeroDotNineSeconds); > + EXPECT_FALSE(kZeroDotNineSeconds > kZeroDotNineSeconds); > +} > + > +TEST(BaseTimeCompare, ZeroDotNineWithOneDotOne) { > + EXPECT_TRUE(kZeroDotNineSeconds < kOneDotOneSeconds); > + EXPECT_TRUE(kZeroDotNineSeconds <= kOneDotOneSeconds); > + EXPECT_FALSE(kZeroDotNineSeconds == kOneDotOneSeconds); > + EXPECT_TRUE(kZeroDotNineSeconds != kOneDotOneSeconds); > + EXPECT_FALSE(kZeroDotNineSeconds >= kOneDotOneSeconds); > + EXPECT_FALSE(kZeroDotNineSeconds > kOneDotOneSeconds); > +} > + > +TEST(BaseTimeCompare, ZeroDotNineWithZeroDotOne) { > + EXPECT_FALSE(kZeroDotNineSeconds < base::kOneHundredMilliseconds); > + EXPECT_FALSE(kZeroDotNineSeconds <= base::kOneHundredMilliseconds); > + EXPECT_FALSE(kZeroDotNineSeconds == base::kOneHundredMilliseconds); > + EXPECT_TRUE(kZeroDotNineSeconds != base::kOneHundredMilliseconds); > + EXPECT_TRUE(kZeroDotNineSeconds >= base::kOneHundredMilliseconds); > + EXPECT_TRUE(kZeroDotNineSeconds > base::kOneHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, OneDotOneWithZeroDotNine) { > + EXPECT_FALSE(kOneDotOneSeconds < kZeroDotNineSeconds); > + EXPECT_FALSE(kOneDotOneSeconds <= kZeroDotNineSeconds); > + EXPECT_FALSE(kOneDotOneSeconds == kZeroDotNineSeconds); > + EXPECT_TRUE(kOneDotOneSeconds != kZeroDotNineSeconds); > + EXPECT_TRUE(kOneDotOneSeconds >= kZeroDotNineSeconds); > + EXPECT_TRUE(kOneDotOneSeconds > kZeroDotNineSeconds); > +} > + > +TEST(BaseTimeCompare, ZeroDotOneWithZeroDotNine) { > + EXPECT_TRUE(base::kOneHundredMilliseconds < kZeroDotNineSeconds); > + EXPECT_TRUE(base::kOneHundredMilliseconds <= kZeroDotNineSeconds); > + EXPECT_FALSE(base::kOneHundredMilliseconds == kZeroDotNineSeconds); > + EXPECT_TRUE(base::kOneHundredMilliseconds != kZeroDotNineSeconds); > + EXPECT_FALSE(base::kOneHundredMilliseconds >= kZeroDotNineSeconds); > + EXPECT_FALSE(base::kOneHundredMilliseconds > kZeroDotNineSeconds); > +} > + > +TEST(BaseTimeCompare, MaxOfTwoWithLargestLast) { > + EXPECT_EQ(base::Max(kZeroDotNineSeconds, kOneDotOneSeconds), > + kOneDotOneSeconds); > + EXPECT_EQ(base::Max(base::kOneHundredMilliseconds, > + base::kTwoHundredMilliseconds), > + base::kTwoHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, MaxOfTwoWithLargestFirst) { > + EXPECT_EQ(base::Max(kOneDotOneSeconds, kZeroDotNineSeconds), > + kOneDotOneSeconds); > + EXPECT_EQ(base::Max(base::kTwoHundredMilliseconds, > + base::kOneHundredMilliseconds), > + base::kTwoHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, MaxOfTwoEqual) { > + EXPECT_EQ(base::Max(kOneDotOneSeconds, kOneDotOneSeconds), > + kOneDotOneSeconds); > +} > + > +TEST(BaseTimeCompare, MaxOfThreeWithLargestLast) { > + EXPECT_EQ(base::Max(kZeroDotNineSeconds, base::kOneSecond, > + kOneDotOneSeconds), > + kOneDotOneSeconds); > + EXPECT_EQ(base::Max(base::kOneHundredMilliseconds, > + base::kTwoHundredMilliseconds, > + base::kThreeHundredMilliseconds), > + base::kThreeHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, MaxOfThreeWithLargestInTheMiddle) { > + EXPECT_EQ(base::Max(kZeroDotNineSeconds, kOneDotOneSeconds, > + base::kOneSecond), > + kOneDotOneSeconds); > + EXPECT_EQ(base::Max(base::kOneHundredMilliseconds, > + base::kThreeHundredMilliseconds, > + base::kTwoHundredMilliseconds), > + base::kThreeHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, MaxOfThreeWithLargestFirst) { > + EXPECT_EQ(base::Max(kOneDotOneSeconds, base::kOneSecond, > + kZeroDotNineSeconds), > + kOneDotOneSeconds); > + EXPECT_EQ(base::Max(base::kThreeHundredMilliseconds, > + base::kOneHundredMilliseconds, > + base::kTwoHundredMilliseconds), > + base::kThreeHundredMilliseconds); > +} > + > +TEST(BaseTimeCompare, MaxOfThreeEqual) { > + EXPECT_EQ(base::Max(kOneDotOneSeconds, kOneDotOneSeconds, > kOneDotOneSeconds), > + kOneDotOneSeconds); > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/time_convert_test.cc > b/osaf/libs/core/cplusplus/base/tests/time_convert_test.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/time_convert_test.cc > @@ -0,0 +1,89 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "base/time.h" > +#include "gtest/gtest.h" > + > +static const timespec kTimespec = { 1576315623, 358743382 }; > +static const timeval kTimeval = { 1576315623, 358743 }; > +static const timespec kTruncatedTimespec = { 1576315623, 358743000 }; > + > +TEST(BaseTimeConvert, TimespecToTimeval) { > + timeval result = base::TimespecToTimeval(kTimespec); > + EXPECT_EQ(result.tv_sec, kTimeval.tv_sec); > + EXPECT_EQ(result.tv_usec, kTimeval.tv_usec); > +} > + > +TEST(BaseTimeConvert, TimevalToTimespec) { > + EXPECT_EQ(base::TimevalToTimespec(kTimeval), kTruncatedTimespec); > +} > + > +TEST(BaseTimeConvert, MillisToTimespec) { > + const timespec expected_result = { 1428499100, 961000000 }; > + EXPECT_EQ(base::MillisToTimespec(1428499100961ull), expected_result); > +} > + > +TEST(BaseTimeConvert, MicrosToTimespec) { > + const timespec expected_result = { 2125428499, 100961000 }; > + EXPECT_EQ(base::MicrosToTimespec(2125428499100961ull), expected_result); > +} > + > +TEST(BaseTimeConvert, NanosToTimespec) { > + const struct timespec expected_result = { 1725125428, 499100961 }; > + EXPECT_EQ(base::NanosToTimespec(1725125428499100961ull), expected_result); > +} > + > +TEST(BaseTimeConvert, DoubleToTimespec) { > + const struct timespec expected_result = { 15714713, 125433700 }; > + const struct timespec expected_result2 = { -15714714, 874566300 }; > + EXPECT_EQ(base::DoubleToTimespec(15714713.1254337), expected_result); > + EXPECT_EQ(base::DoubleToTimespec(-15714713.1254337), expected_result2); > +} > + > +TEST(BaseTimeConvert, DurationToTimespec) { > + const struct timespec expected_result = { 1725125428, 499100961 }; > + std::chrono::nanoseconds duration{1725125428499100961ull}; > + EXPECT_EQ(base::DurationToTimespec(duration), expected_result); > +} > + > +TEST(BaseTimeConvert, TimespecToMillis) { > + const struct timespec ts = { 1428499100, 961923266 }; > + EXPECT_EQ(base::TimespecToMillis(ts), 1428499100961ull); > +} > + > +TEST(BaseTimeConvert, TimespecToMicros) { > + const struct timespec ts = { 1125428499, 100961923 }; > + EXPECT_EQ(base::TimespecToMicros(ts), 1125428499100961ull); > +} > + > +TEST(BaseTimeConvert, TimespecToNanos) { > + const struct timespec ts = { 1725125428, 499100961 }; > + EXPECT_EQ(base::TimespecToNanos(ts), 1725125428499100961ull); > +} > + > +TEST(BaseTimeConvert, TimespecToDouble) { > + const struct timespec ts = { 15714713, 125433700 }; > + const struct timespec ts2 = { -15714714, 874566300 }; > + EXPECT_EQ(base::TimespecToDouble(ts), 15714713.1254337); > + EXPECT_EQ(base::TimespecToDouble(ts2), -15714713.1254337); > +} > + > +TEST(BaseTimeConvert, TimespecToDuration) { > + const struct timespec ts = { 1725125428, 499100961 }; > + std::chrono::nanoseconds expected_result{1725125428499100961ull}; > + EXPECT_EQ(base::TimespecToDuration(ts), expected_result); > +} > diff --git a/osaf/libs/core/cplusplus/base/tests/time_subtract_test.cc > b/osaf/libs/core/cplusplus/base/tests/time_subtract_test.cc > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/tests/time_subtract_test.cc > @@ -0,0 +1,52 @@ > +/* -*- OpenSAF -*- > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#include "base/time.h" > +#include "gtest/gtest.h" > + > [HansN] perhaps unamed namespaces can be used instead of static? > +static const timespec kOneDotOneSeconds = { 1, 100000000 }; > +static const timespec kZeroDotTwoSeconds = { 0, 200000000 }; > +static const timespec kZeroDotNineSeconds = { 0, 900000000 }; > +static const timespec number1 = { 1576315623, 358743382 }; > +static const timespec number2 = { 279394477, 639614599 }; > +static const timespec difference = { 1296921145, 719128783 }; > + > +TEST(BaseTimeSubtract, ZeroMinusZero) { > + timespec result = base::kZeroSeconds - base::kZeroSeconds; > + EXPECT_TRUE(result == base::kZeroSeconds); > +} > + > +TEST(BaseTimeSubtract, FifteenMinusFive) { > + timespec result = base::kFifteenSeconds - base::kFiveSeconds; > + EXPECT_TRUE(result == base::kTenSeconds); > +} > + > +TEST(BaseTimeSubtract, OneDotOneMinusZeroDotTwo) { > + timespec result = kOneDotOneSeconds - kZeroDotTwoSeconds; > + EXPECT_TRUE(result == kZeroDotNineSeconds); > +} > + > +TEST(BaseTimeSubtract, SubtractRandomNumbers) { > + timespec result = number1 - number2; > + EXPECT_TRUE(result == difference); > +} > + > +TEST(BaseTimeSubtract, FirstParameterAndResultAtSameAddress) { > + timespec result = number1; > + result -= number2; > + EXPECT_TRUE(result == difference); > +} > diff --git a/osaf/libs/core/cplusplus/base/time.h > b/osaf/libs/core/cplusplus/base/time.h > new file mode 100644 > --- /dev/null > +++ b/osaf/libs/core/cplusplus/base/time.h > @@ -0,0 +1,275 @@ > +/* > + * > + * (C) Copyright 2016 The OpenSAF Foundation > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > + * under the GNU Lesser General Public License Version 2.1, February 1999. > + * The complete license can be accessed from the following location: > + * http://opensource.org/licenses/lgpl-license.php > + * See the Copying file included with the OpenSAF distribution for full > + * licensing terms. > + * > + * Author(s): Ericsson AB > + * > + */ > + > +#ifndef OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TIME_H_ > +#define OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TIME_H_ > + > +#include <stdint.h> > +#include <cassert> > +#include <chrono> > +#include <climits> > +#include <ctime> > +#include "osaf_time.h" > + > +static inline bool operator<(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) < 0; > +} > + > +static inline bool operator<=(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) <= 0; > +} > + > +static inline bool operator==(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) == 0; > +} > + > +static inline bool operator!=(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) != 0; > +} > + > +static inline bool operator>=(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) >= 0; > +} > + > +static inline bool operator>(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) > 0; > +} > + > +static inline timespec operator+(const timespec& ts1, const timespec& ts2) { > + timespec sum; > + osaf_timespec_add(&ts1, &ts2, &sum); > + return sum; > +} > + > +static inline timespec operator-(const timespec& ts1, const timespec& ts2) { > + timespec difference; > + assert(ts1 >= ts2); > + osaf_timespec_subtract(&ts1, &ts2, &difference); > + return difference; > +} > + > +static inline timespec& operator+=(timespec& ts1, const timespec& ts2) { > + osaf_timespec_add(&ts1, &ts2, &ts1); > + return ts1; > +} > + > +static inline timespec& operator-=(timespec& ts1, const timespec& ts2) { > + assert(ts1 >= ts2); > + osaf_timespec_subtract(&ts1, &ts2, &ts1); > + return ts1; > +} > + > +namespace base { > + > +constexpr static const timespec kZeroSeconds{ 0, 0 }; > +constexpr static const timespec kOneMillisecond{ 0, 1000000 }; > +constexpr static const timespec kTenMilliseconds{ 0, 10000000 }; > +constexpr static const timespec kTwentyMilliseconds{ 0, 20000000 }; > +constexpr static const timespec kThirtyMilliseconds{ 0, 30000000 }; > +constexpr static const timespec kFourtyMilliseconds{ 0, 40000000 }; > +constexpr static const timespec kFiftyMilliseconds{ 0, 50000000 }; > +constexpr static const timespec kOneHundredMilliseconds{ 0, 100000000 }; > +constexpr static const timespec kTwoHundredMilliseconds{ 0, 200000000 }; > +constexpr static const timespec kThreeHundredMilliseconds{ 0, 300000000 }; > +constexpr static const timespec kFourHundredMilliseconds{ 0, 400000000 }; > +constexpr static const timespec kFiveHundredMilliseconds{ 0, 500000000 }; > +constexpr static const timespec kOneSecond{ 1, 0 }; > +constexpr static const timespec kFiveSeconds{ 5, 0 }; > +constexpr static const timespec kTenSeconds{ 10, 0 }; > +constexpr static const timespec kFifteenSeconds{ 15, 0 }; > +constexpr static const timespec kTwentySeconds{ 20, 0 }; > +constexpr static const timespec kTwentyfiveSeconds{ 25, 0 }; > +constexpr static const timespec kThirtySeconds{ 30, 0 }; > +constexpr static const timespec kOneMinute{ 1 * 60, 0 }; > +constexpr static const timespec kFiveMinutes{ 5 * 60, 0 }; > +constexpr static const timespec kTenMinutes{ 10 * 60, 0 }; > +constexpr static const timespec kFifteenMinutes{ 15 * 60, 0 }; > +constexpr static const timespec kTwentyMinutes{ 20 * 60, 0 }; > +constexpr static const timespec kTwentyfiveMinutes{ 25 * 60, 0 }; > +constexpr static const timespec kThirtyMinutes{ 30 * 60, 0 }; > +constexpr static const timespec kOneHour{ 60 * 60, 0 }; > +constexpr static const timespec kTimespecMax{ sizeof(time_t) == 8 ? > INT64_MAX : > + INT32_MAX, 999999999 }; > + > +/** > + * Read the current value of the system's real-time clock. For more > + * information, refer to the POSIX function clock_gettime() and the clock id > + * CLOCK_REALTIME. > + */ > +static inline timespec ReadRealtimeClock() { > + timespec ts; > + osaf_clock_gettime(CLOCK_REALTIME, &ts); > + return ts; > +} > + > +/** > + * Read the current value of the system's monotonic clock. For more > + * information, refer to the POSIX function clock_gettime() and the clock id > + * CLOCK_MONOTONIC. > + */ > +static inline timespec ReadMonotonicClock() { > + timespec ts; > + osaf_clock_gettime(CLOCK_MONOTONIC, &ts); > + return ts; > +} > + > +/** > + * Suspend execution of the calling thread for the specified @a duration. > + */ > +static inline void Sleep(const timespec& duration) { > + osaf_nanosleep(&duration); > +} > + > +/** > + * Convert the specified @a duration to a timespec structure. > + */ > +template<class Rep, class Period> > +static inline timespec DurationToTimespec( > + const std::chrono::duration<Rep, Period>& duration) { > + timespec ts; > + std::chrono::nanoseconds nanos = duration; > + osaf_nanos_to_timespec(nanos.count(), &ts); > + return ts; > +} > + > +/** > + * Convert the specified timeval structure to a timespec structure. > + */ > +static inline timespec TimevalToTimespec(const timeval& tv) { > + timespec ts; > + osaf_timeval_to_timespec(&tv, &ts); > + return ts; > +} > + > +/** > + * Convert the specified number of @a seconds to a timespec structure. > + */ > +static inline timespec DoubleToTimespec(double seconds) { > + timespec ts; > + osaf_double_to_timespec(seconds, &ts); > + return ts; > +} > + > +/** > + * Convert the specified number of @a milliseconds to a timespec structure. > + */ > +static inline timespec MillisToTimespec(uint64_t milliseconds) { > + timespec ts; > + osaf_millis_to_timespec(milliseconds, &ts); > + return ts; > +} > + > +/** > + * Convert the specified number of @a microseconds to a timespec structure. > + */ > +static inline timespec MicrosToTimespec(uint64_t microseconds) { > + timespec ts; > + osaf_micros_to_timespec(microseconds, &ts); > + return ts; > +} > + > +/** > + * Convert the specified number of @a nanoseconds to a timespec structure. > + */ > +static inline timespec NanosToTimespec(uint64_t nanoseconds) { > + timespec ts; > + osaf_nanos_to_timespec(nanoseconds, &ts); > + return ts; > +} > + > +/** > + * Convert the specified timespec structure @a ts to a duration with > nanosecond > + * resolution. > + */ > +static inline std::chrono::nanoseconds TimespecToDuration(const timespec& > ts) { > + return std::chrono::nanoseconds{osaf_timespec_to_nanos(&ts)}; > +} > + > +/** > + * Convert the specified timeval structure to a timespec structure. > + */ > +static inline timeval TimespecToTimeval(const timespec& ts) { > + timeval tv; > + osaf_timespec_to_timeval(&ts, &tv); > + return tv; > +} > + > +/** > + * Convert the specified timespec structure @a ts to a double representing > time > + * in the unit of seconds. > + */ > +static inline double TimespecToDouble(const timespec& ts) { > + return osaf_timespec_to_double(&ts); > +} > + > +/** > + * Convert the specified timespec structure @a ts to an integer representing > + * time in the unit of milliseconds. > + */ > +static inline uint64_t TimespecToMillis(const timespec& ts) { > + return osaf_timespec_to_millis(&ts); > +} > + > +/** > + * Convert the specified timespec structure @a ts to an integer representing > + * time in the unit of microseconds. > + */ > +static inline uint64_t TimespecToMicros(const timespec& ts) { > + return osaf_timespec_to_micros(&ts); > +} > + > +/** > + * Convert the specified timespec structure @a ts to an integer representing > + * time in the unit of nanoseconds. > + */ > +static inline uint64_t TimespecToNanos(const timespec& ts) { > + return osaf_timespec_to_nanos(&ts); > +} > + > +/** > + * Return the smallest of the two specified timespec structures. > + */ > +static inline timespec Min(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) <= 0 ? ts1 : ts2; > +} > + > +/** > + * Return the smallest of the three specified timespec structures. > + */ > +static inline timespec Min(const timespec& ts1, const timespec& ts2, > + const timespec& ts3) { > + return osaf_timespec_compare(&ts1, &ts2) <= 0 ? Min(ts1, ts3) : Min(ts2, > ts3); > +} > + > +/** > + * Return the largest of the two specified timespec structures. > + */ > +static inline timespec Max(const timespec& ts1, const timespec& ts2) { > + return osaf_timespec_compare(&ts1, &ts2) >= 0 ? ts1 : ts2; > +} > + > +/** > + * Return the largest of the three specified timespec structures. > + */ > +static inline timespec Max(const timespec& ts1, const timespec& ts2, > + const timespec& ts3) { > + return osaf_timespec_compare(&ts1, &ts2) >= 0 ? Max(ts1, ts3) : Max(ts2, > ts3); > +} > + > +} // namespace base > + > +#endif /* OPENSAF_OSAF_LIBS_CORE_CPLUSPLUS_BASE_TIME_H_ */ > > ------------------------------------------------------------------------------ > Site24x7 APM Insight: Get Deep Visibility into Application Performance > APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month > Monitor end-to-end web transactions and take corrective actions now > Troubleshoot faster and improve end-user experience. Signup Now! > http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140 > _______________________________________________ > Opensaf-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/opensaf-devel ------------------------------------------------------------------------------ Transform Data into Opportunity. Accelerate data analysis in your applications with Intel Data Analytics Acceleration Library. Click to learn more. http://pubads.g.doubleclick.net/gampad/clk?id=278785471&iu=/4140 _______________________________________________ Opensaf-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/opensaf-devel
