diff options
author | Andrew Geissler <andrewg@us.ibm.com> | 2017-04-03 13:31:13 -0500 |
---|---|---|
committer | Andrew Geissler <andrewg@us.ibm.com> | 2017-05-09 12:51:59 -0500 |
commit | 8315970370d63b101bd0bd579bc1f697a3c8d07c (patch) | |
tree | 856438abae898d4edd29a6df9e6ccf5e1c28aa20 /timer.cpp | |
parent | 857f54b71198dcb5a1d5acae98f0c0cb78298694 (diff) | |
download | phosphor-host-ipmid-8315970370d63b101bd0bd579bc1f697a3c8d07c.tar.gz phosphor-host-ipmid-8315970370d63b101bd0bd579bc1f697a3c8d07c.zip |
Add timeout support to host control
On timeout, send error signal for all commands within the queue
Change-Id: Ic995fd4b057bd83f121a3deec405a26e0991e9a2
Signed-off-by: Andrew Geissler <andrewg@us.ibm.com>
Diffstat (limited to 'timer.cpp')
-rw-r--r-- | timer.cpp | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/timer.cpp b/timer.cpp new file mode 100644 index 0000000..4e8fd9a --- /dev/null +++ b/timer.cpp @@ -0,0 +1,108 @@ +#include <chrono> +#include <phosphor-logging/log.hpp> +#include "timer.hpp" +namespace phosphor +{ +namespace ipmi +{ + +using namespace phosphor::logging; + +// Initializes the timer object +void Timer::initialize() +{ + // This can not be called more than once. + if (eventSource) + { + throw std::runtime_error("Timer already initialized"); + } + + // Add infinite expiration time + auto r = sd_event_add_time(timeEvent, &eventSource, + CLOCK_MONOTONIC, // Time base + UINT64_MAX, // Expire time - way long time + 0, // Use default event accuracy + timeoutHandler, // Callback handler on timeout + this); // User data + if (r < 0) + { + log<level::ERR>("Failure to set initial expiration time value", + entry("ERROR=%s", strerror(-r))); + + throw std::runtime_error("Timer initialization failed"); + } + + // Disable the timer for now + r = setTimer(SD_EVENT_OFF); + if (r < 0) + { + log<level::ERR>("Failure to disable timer", + entry("ERROR=%s", strerror(-r))); + + throw std::runtime_error("Disabling the timer failed"); + } + return; +} + +/** @brief callback handler on timeout */ +int Timer::timeoutHandler(sd_event_source* eventSource, + uint64_t usec, void* userData) +{ + auto timer = static_cast<Timer*>(userData); + timer->expired = true; + + // Call optional user call back function if available + if(timer->userCallBack) + { + timer->userCallBack(); + } + + log<level::INFO>("Timer expired"); + return 0; +} + +// Gets the time from steady_clock +std::chrono::microseconds Timer::getTime() +{ + using namespace std::chrono; + auto usec = steady_clock::now().time_since_epoch(); + return duration_cast<microseconds>(usec); +} + +// Enables or disables the timer +int Timer::setTimer(int action) +{ + return sd_event_source_set_enabled(eventSource, action); +} + +// Sets the time and arms the timer +int Timer::startTimer(std::chrono::microseconds timeValue) +{ + // Disable the timer + setTimer(SD_EVENT_OFF); + + // Get the current MONOTONIC time and add the delta + auto expireTime = getTime() + timeValue; + + // Set the time + auto r = sd_event_source_set_time(eventSource, expireTime.count()); + if (r < 0) + { + log<level::ERR>("Failure to set timer", + entry("ERROR=%s", strerror(-r))); + return r; + } + + // A ONESHOT timer means that when the timer goes off, + // its moves to disabled state. + r = setTimer(SD_EVENT_ONESHOT); + if (r < 0) + { + log<level::ERR>("Failure to start timer", + entry("ERROR=%s", strerror(-r))); + } + return r; +} + +} // namespace ipmi +} // namespace phosphor |