blob: 3dfe56006a7d544dec75ea672a893facfe88dcf0 [file] [log] [blame]
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +05301#include "timer.hpp"
Patrick Venture8f6c5152018-09-11 17:45:33 -07002
3#include <systemd/sd-event.h>
4
5#include <chrono>
6#include <phosphor-logging/elog-errors.hpp>
7#include <phosphor-logging/elog.hpp>
8#include <phosphor-logging/log.hpp>
9#include <xyz/openbmc_project/Common/error.hpp>
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053010namespace phosphor
11{
12namespace watchdog
13{
14
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053015// For throwing exception
16using namespace phosphor::logging;
Patrick Venture8f6c5152018-09-11 17:45:33 -070017using InternalFailure =
18 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053019
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053020// Initializes the timer object
21void Timer::initialize()
22{
23 // This can not be called more than once.
24 if (eventSource.get())
25 {
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053026 log<level::ERR>("Timer already initialized");
27 elog<InternalFailure>();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053028 }
29
30 // Add infinite expiration time
31 decltype(eventSource.get()) sourcePtr = nullptr;
Patrick Venture8f6c5152018-09-11 17:45:33 -070032 auto r = sd_event_add_time(event.get(), &sourcePtr,
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053033 CLOCK_MONOTONIC, // Time base
34 UINT64_MAX, // Expire time - way long time
35 0, // Use default event accuracy
36 timeoutHandler, // Callback handler on timeout
37 this); // User data
38 eventSource.reset(sourcePtr);
39
40 if (r < 0)
41 {
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053042 log<level::ERR>("Timer initialization failed");
43 elog<InternalFailure>();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053044 }
45
46 // Disable the timer for now
47 setEnabled<std::false_type>();
48}
49
50// callback handler on timeout
Patrick Venture8f6c5152018-09-11 17:45:33 -070051int Timer::timeoutHandler(sd_event_source* eventSource, uint64_t usec,
52 void* userData)
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053053{
54 using namespace phosphor::logging;
55
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +053056 log<level::INFO>("Timer Expired");
57
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053058 auto timer = static_cast<Timer*>(userData);
59 timer->expire = true;
60
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +053061 // Call an optional callback function
Patrick Venture8f6c5152018-09-11 17:45:33 -070062 if (timer->userCallBack)
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +053063 {
64 timer->userCallBack();
65 }
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053066 return 0;
67}
68
69// Gets the time from steady_clock
70std::chrono::microseconds Timer::getCurrentTime()
71{
72 using namespace std::chrono;
73 auto usec = steady_clock::now().time_since_epoch();
74 return duration_cast<microseconds>(usec);
75}
76
77// Sets the expiration time and arms the timer
78void Timer::start(std::chrono::microseconds usec)
79{
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053080 using namespace std::chrono;
81
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053082 // Get the current MONOTONIC time and add the delta
83 auto expireTime = getCurrentTime() + usec;
84
85 // Set the time
Patrick Venture8f6c5152018-09-11 17:45:33 -070086 auto r = sd_event_source_set_time(eventSource.get(), expireTime.count());
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053087 if (r < 0)
88 {
Patrick Venture8f6c5152018-09-11 17:45:33 -070089 log<level::ERR>(
90 "Error setting the expiration time",
91 entry("MSEC=%llu", duration_cast<milliseconds>(usec).count()));
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053092 elog<InternalFailure>();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053093 }
94}
95
96// Returns current timer enablement type
97int Timer::getEnabled() const
98{
99 int enabled{};
100 auto r = sd_event_source_get_enabled(eventSource.get(), &enabled);
101 if (r < 0)
102 {
Gunnar Mills7512a122018-04-08 14:30:36 -0500103 log<level::ERR>("Error getting current timer type enablement state");
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530104 elog<InternalFailure>();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530105 }
106 return enabled;
107}
108
109// Enables / disables the timer
110void Timer::setEnabled(int type)
111{
112 auto r = sd_event_source_set_enabled(eventSource.get(), type);
113 if (r < 0)
114 {
Patrick Venture8f6c5152018-09-11 17:45:33 -0700115 log<level::ERR>("Error setting the timer type", entry("TYPE=%d", type));
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530116 elog<InternalFailure>();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530117 }
118}
119
120// Returns time remaining before expiration
121std::chrono::microseconds Timer::getRemaining() const
122{
123 uint64_t next = 0;
124 auto r = sd_event_source_get_time(eventSource.get(), &next);
125 if (r < 0)
126 {
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530127 log<level::ERR>("Error fetching remaining time to expire");
128 elog<InternalFailure>();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530129 }
130 return std::chrono::microseconds(next);
131}
132
133} // namespace watchdog
134} // namespace phosphor