From 2de67cf4d19e2e433e1ea56583e0d5ae043b3d79 Mon Sep 17 00:00:00 2001 From: Matt Spinler Date: Thu, 27 Apr 2017 11:07:53 -0500 Subject: phosphor-fan: Create timer class This class can be used to call an arbitrary function after a certain amount of time, which is set in microseconds. Change-Id: Ifd65bbf0c3482db4e37efc3b1ccc868e62fa0afa Signed-off-by: Matt Spinler --- timer.cpp | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 timer.cpp (limited to 'timer.cpp') diff --git a/timer.cpp b/timer.cpp new file mode 100644 index 0000000..41a8138 --- /dev/null +++ b/timer.cpp @@ -0,0 +1,172 @@ +/** + * Copyright © 2017 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "timer.hpp" + +namespace phosphor +{ +namespace fan +{ +namespace util +{ + +using namespace phosphor::logging; + +Timer::Timer(EventPtr& events, + std::function callbackFunc) : + timeEvent(events), + callback(callbackFunc), + timeout(0) +{ + sd_event_source* source = nullptr; + + // Start with an infinite expiration time + auto r = sd_event_add_time(timeEvent.get(), + &source, + 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("Timer::Timer failed call to sd_event_add_time", + entry("ERROR=%s", strerror(-r))); + //TODO openbmc/openbmc#1555 throw an elog + throw std::runtime_error("Timer initialization failed"); + } + + eventSource.reset(source); + + //Ensure timer isn't running + setTimer(SD_EVENT_OFF); +} + + +Timer::~Timer() +{ + setTimer(SD_EVENT_OFF); +} + + +int Timer::timeoutHandler(sd_event_source* eventSource, + uint64_t usec, void* userData) +{ + auto timer = static_cast(userData); + + if (timer->type == TimerType::repeating) + { + //Set the next expiration time + timer->setTimeout(); + } + + timer->callback(); + + return 0; +} + + +std::chrono::microseconds Timer::getTime() +{ + using namespace std::chrono; + auto now = steady_clock::now().time_since_epoch(); + return duration_cast(now); +} + + +void Timer::setTimer(int action) +{ + auto r = sd_event_source_set_enabled(eventSource.get(), action); + if (r < 0) + { + log("Failed call to sd_event_source_set_enabled", + entry("ERROR=%s", strerror(-r)), + entry("ACTION=%d", action)); + //TODO openbmc/openbmc#1555 throw an elog + throw std::runtime_error("Failed call to sd_event_source_set_enabled"); + } +} + + +void Timer::stop() +{ + setTimer(SD_EVENT_OFF); +} + + +bool Timer::running() +{ + int status = 0; + + //returns SD_EVENT_OFF, SD_EVENT_ON, or SD_EVENT_ONESHOT + auto r = sd_event_source_get_enabled(eventSource.get(), &status); + if (r < 0) + { + log("Failed call to sd_event_source_get_enabled", + entry("ERROR=%s", strerror(-r))); + //TODO openbmc/openbmc#1555 throw an elog + throw std::runtime_error("Failed call to sd_event_source_get_enabled"); + } + + return (status != SD_EVENT_OFF); +} + + +void Timer::setTimeout() +{ + //Get the current time and add the delta + static_assert(std::is_same::value, + "Timer::getTime() is the wrong type"); + static_assert(std::is_same::value, + "Timer::timeout is the wrong type"); + + auto expireTime = getTime() + timeout; + + //Set the time + auto r = sd_event_source_set_time(eventSource.get(), expireTime.count()); + if (r < 0) + { + log("Failed call to sd_event_source_set_time", + entry("ERROR=%s", strerror(-r))); + //TODO openbmc/openbmc#1555 throw an elog + throw std::runtime_error("Failed call to sd_event_source_set_time"); + } +} + + +void Timer::start(std::chrono::microseconds timeValue, + TimerType timerType) +{ + type = timerType; + + // Disable the timer + setTimer(SD_EVENT_OFF); + + //Rearm the timer + timeout = timeValue; + setTimeout(); + + setTimer((type == TimerType::oneshot) ? SD_EVENT_ONESHOT : SD_EVENT_ON); +} + + +} +} +} -- cgit v1.2.1