summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishwanatha Subbanna <vishwa@linux.vnet.ibm.com>2017-05-29 17:03:33 +0530
committerVishwanatha Subbanna <vishwa@linux.vnet.ibm.com>2017-06-02 16:36:32 +0530
commit7e146557a27508a07ce2abeaf22871daab94c6d8 (patch)
treeff6df00d0b00b22230b85428672107bce394027a
parent15b1dc1788fdbe6b473a0fac6b14922304716555 (diff)
downloadphosphor-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.am12
-rw-r--r--configure.ac3
-rw-r--r--mainapp.cpp28
-rw-r--r--timer.cpp118
-rw-r--r--timer.hpp132
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
OpenPOWER on IntegriCloud