diff options
author | Matt Spinler <spinler@us.ibm.com> | 2017-04-27 11:07:53 -0500 |
---|---|---|
committer | Matt Spinler <spinler@us.ibm.com> | 2017-05-11 13:52:45 -0500 |
commit | 2de67cf4d19e2e433e1ea56583e0d5ae043b3d79 (patch) | |
tree | 2d982ce65908bd1080a74967276bb5fbd9f9441e /timer.cpp | |
parent | 77d32d1b0b780b9ac773bc49a6c74c19508ff8e8 (diff) | |
download | phosphor-fan-presence-2de67cf4d19e2e433e1ea56583e0d5ae043b3d79.tar.gz phosphor-fan-presence-2de67cf4d19e2e433e1ea56583e0d5ae043b3d79.zip |
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 <spinler@us.ibm.com>
Diffstat (limited to 'timer.cpp')
-rw-r--r-- | timer.cpp | 172 |
1 files changed, 172 insertions, 0 deletions
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 <chrono> +#include <phosphor-logging/log.hpp> +#include <type_traits> +#include "timer.hpp" + +namespace phosphor +{ +namespace fan +{ +namespace util +{ + +using namespace phosphor::logging; + +Timer::Timer(EventPtr& events, + std::function<void()> 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<level::ERR>("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<Timer*>(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<microseconds>(now); +} + + +void Timer::setTimer(int action) +{ + auto r = sd_event_source_set_enabled(eventSource.get(), action); + if (r < 0) + { + log<level::ERR>("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<level::ERR>("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<decltype(getTime()), + std::chrono::microseconds>::value, + "Timer::getTime() is the wrong type"); + static_assert(std::is_same<decltype(timeout), + std::chrono::microseconds>::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<level::ERR>("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); +} + + +} +} +} |