diff options
author | Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com> | 2017-05-29 17:03:33 +0530 |
---|---|---|
committer | Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com> | 2017-06-02 16:36:32 +0530 |
commit | 7e146557a27508a07ce2abeaf22871daab94c6d8 (patch) | |
tree | ff6df00d0b00b22230b85428672107bce394027a | |
parent | 15b1dc1788fdbe6b473a0fac6b14922304716555 (diff) | |
download | phosphor-watchdog-7e146557a27508a07ce2abeaf22871daab94c6d8.tar.gz phosphor-watchdog-7e146557a27508a07ce2abeaf22871daab94c6d8.zip |
Add timer class support
Watchdog implementation uses sd_event_timer at the backend and this
commit has that timer backend support.
Change-Id: Ib6dbd5d6bb617c20d7361e0852a916aa506d5aad
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
-rw-r--r-- | Makefile.am | 12 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | mainapp.cpp | 28 | ||||
-rw-r--r-- | timer.cpp | 118 | ||||
-rw-r--r-- | timer.hpp | 132 |
5 files changed, 291 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index 370d024..888f8cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,13 @@ sbin_PROGRAMS = phosphor-watchdog +noinst_HEADERS = timer.hpp + phosphor_watchdog_SOURCES = \ - argument.cpp \ - mainapp.cpp + argument.cpp \ + timer.cpp \ + mainapp.cpp + +phosphor_watchdog_LDFLAGS = $(SYSTEMD_LIBS) \ + ${PHOSPHOR_LOGGING_LIBS} +phosphor_watchdog_CXXFLAGS = $(SYSTEMD_CFLAGS)\ + ${PHOSPHOR_LOGGING_CFLAGS} diff --git a/configure.ac b/configure.ac index 2f48a68..2f06b7b 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,9 @@ AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS]) # For linking LT_INIT +PKG_CHECK_MODULES([SYSTEMD], [libsystemd >= 221], [], [AC_MSG_ERROR(["systemd required and not found"])]) +PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],, [AC_MSG_ERROR([Could not find phosphor-logging...openbmc/phosphor-logging package required])]) + # Create configured output AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/mainapp.cpp b/mainapp.cpp index 19aeb6a..4ab811c 100644 --- a/mainapp.cpp +++ b/mainapp.cpp @@ -15,7 +15,9 @@ */ #include <iostream> +#include <phosphor-logging/log.hpp> #include "argument.hpp" +#include "timer.hpp" static void exitWithError(const char* err, char** argv) { @@ -26,6 +28,8 @@ static void exitWithError(const char* err, char** argv) int main(int argc, char** argv) { + using namespace phosphor::logging; + // Read arguments. auto options = phosphor::watchdog::ArgumentParser(argc, argv); @@ -48,5 +52,29 @@ int main(int argc, char** argv) // on meeting a condition. auto target = (options)["target"]; + sd_event* event = nullptr; + auto r = sd_event_default(&event); + if (r < 0) + { + log<level::ERR>("Error creating a default sd_event handler"); + return r; + } + phosphor::watchdog::EventPtr eventP{event}; + event = nullptr; + + // TODO: Creating the timer object would be inside watchdog implementation. + // Putting this here for completion of this piece + phosphor::watchdog::Timer timer(eventP); + + while(!timer.expired()) + { + // -1 denotes wait for ever + r = sd_event_run(eventP.get(), (uint64_t)-1); + if (r < 0) + { + log<level::ERR>("Error waiting for events"); + return -1; + } + } return 0; } diff --git a/timer.cpp b/timer.cpp new file mode 100644 index 0000000..bf1a470 --- /dev/null +++ b/timer.cpp @@ -0,0 +1,118 @@ +#include <chrono> +#include <systemd/sd-event.h> +#include <phosphor-logging/log.hpp> +#include "timer.hpp" +namespace phosphor +{ +namespace watchdog +{ + +// Initializes the timer object +void Timer::initialize() +{ + // This can not be called more than once. + if (eventSource.get()) + { + // TODO: Need to throw elog exception stating its already added. + throw std::runtime_error("Timer already initialized"); + } + + // Add infinite expiration time + decltype(eventSource.get()) sourcePtr = nullptr; + auto r = sd_event_add_time(event.get(), + &sourcePtr, + CLOCK_MONOTONIC, // Time base + UINT64_MAX, // Expire time - way long time + 0, // Use default event accuracy + timeoutHandler, // Callback handler on timeout + this); // User data + eventSource.reset(sourcePtr); + + if (r < 0) + { + // TODO: throw elog exception + throw std::runtime_error("Timer initialization failed"); + } + + // Disable the timer for now + setEnabled<std::false_type>(); +} + +// callback handler on timeout +int Timer::timeoutHandler(sd_event_source* eventSource, + uint64_t usec, void* userData) +{ + using namespace phosphor::logging; + + auto timer = static_cast<Timer*>(userData); + timer->expire = true; + + log<level::INFO>("Timer Expired"); + + //TODO: Need to call user callback function. + return 0; +} + +// Gets the time from steady_clock +std::chrono::microseconds Timer::getCurrentTime() +{ + using namespace std::chrono; + auto usec = steady_clock::now().time_since_epoch(); + return duration_cast<microseconds>(usec); +} + +// Sets the expiration time and arms the timer +void Timer::start(std::chrono::microseconds usec) +{ + // Get the current MONOTONIC time and add the delta + auto expireTime = getCurrentTime() + usec; + + // Set the time + auto r = sd_event_source_set_time(eventSource.get(), + expireTime.count()); + if (r < 0) + { + // TODO throw elog exception + throw std::runtime_error("Error setting the expiration time"); + } +} + +// Returns current timer enablement type +int Timer::getEnabled() const +{ + int enabled{}; + auto r = sd_event_source_get_enabled(eventSource.get(), &enabled); + if (r < 0) + { + // TODO: Need to throw elog exception + throw std::runtime_error("Error geting current time enablement state"); + } + return enabled; +} + +// Enables / disables the timer +void Timer::setEnabled(int type) +{ + auto r = sd_event_source_set_enabled(eventSource.get(), type); + if (r < 0) + { + // TODO: Need to throw elog exception + throw std::runtime_error("Error altering enabled property"); + } +} + +// Returns time remaining before expiration +std::chrono::microseconds Timer::getRemaining() const +{ + uint64_t next = 0; + auto r = sd_event_source_get_time(eventSource.get(), &next); + if (r < 0) + { + // TODO: Need to throw elog exception + throw std::runtime_error("Error altering enabled property"); + } + return std::chrono::microseconds(next); +} + +} // namespace watchdog +} // namespace phosphor diff --git a/timer.hpp b/timer.hpp new file mode 100644 index 0000000..49580d7 --- /dev/null +++ b/timer.hpp @@ -0,0 +1,132 @@ +#pragma once + +#include <memory> +#include <chrono> +#include <systemd/sd-event.h> +namespace phosphor +{ +namespace watchdog +{ + +/* Need a custom deleter for freeing up sd_event */ +struct EventDeleter +{ + void operator()(sd_event* event) const + { + event = sd_event_unref(event); + } +}; +using EventPtr = std::unique_ptr<sd_event, EventDeleter>; + +/* Need a custom deleter for freeing up sd_event_source */ +struct EventSourceDeleter +{ + void operator()(sd_event_source* eventSource) const + { + eventSource = sd_event_source_unref(eventSource); + } +}; +using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>; + +/** @class Timer + * @brief Manages starting timers and handling timeouts + */ +class Timer +{ + public: + Timer() = delete; + ~Timer() = default; + Timer(const Timer&) = delete; + Timer& operator=(const Timer&) = delete; + Timer(Timer&&) = delete; + Timer& operator=(Timer&&) = delete; + + /** @brief Constructs timer object + * + * @param[in] event - sd_event unique pointer reference + */ + Timer(EventPtr& event) + : event(event) + { + // Initialize the timer + initialize(); + } + + /** @brief Tells whether the timer is expired or not */ + inline auto expired() const + { + return expire; + } + + /** @brief Returns the current Timer enablement type */ + int getEnabled() const; + + /** @brief Enables / disables the timer. + * <T> is an integral constant boolean + */ + template <typename T> void setEnabled() + { + constexpr auto type = T::value ? SD_EVENT_ONESHOT : SD_EVENT_OFF; + return setEnabled(type); + } + + /** @brief Returns time remaining in usec before expiration + * which is an offset to current steady clock + */ + std::chrono::microseconds getRemaining() const; + + /** @brief Starts the timer with specified expiration value. + * std::steady_clock is used for base time. + * + * @param[in] usec - Microseconds from the current time + * before expiration. + * + * @return None. + * + * @error Throws exception + */ + void start(std::chrono::microseconds usec); + + /** @brief Gets the current time from steady clock */ + static std::chrono::microseconds getCurrentTime(); + + private: + /** @brief Reference to sd_event unique pointer */ + EventPtr& event; + + /** @brief event source */ + EventSourcePtr eventSource; + + /** @brief Set to true when the timeoutHandler is called into */ + bool expire = false; + + /** @brief Initializes the timer object with infinite + * expiration time and sets up the callback handler + * + * @return None. + * + * @error Throws exception + */ + void initialize(); + + /** @brief Callback function when timer goes off + * + * @param[in] eventSource - Source of the event + * @param[in] usec - time in microseconds + * @param[in] userData - User data pointer + * + */ + static int timeoutHandler(sd_event_source* eventSource, + uint64_t usec, void* userData); + + /** @brief Enables / disables the timer + * + * @param[in] type - Timer type. + * This implementation uses only SD_EVENT_OFF + * and SD_EVENT_ONESHOT + */ + void setEnabled(int type); +}; + +} // namespace watchdog +} // namespace phosphor |