blob: f1887fd214aebb20a6d0d7374c656b889b0f294f [file] [log] [blame]
Vernon Mauery9e801a22018-10-12 13:20:49 -07001#include "timer.hpp"
2
Ratan Gupta40801362018-03-12 16:21:37 +05303#include <chrono>
4#include <phosphor-logging/log.hpp>
Ratan Gupta40801362018-03-12 16:21:37 +05305namespace phosphor
6{
7namespace ipmi
8{
9
10using namespace phosphor::logging;
11
12// Initializes the timer object
13void Timer::initialize()
14{
15 // This can not be called more than once.
16 if (eventSource)
17 {
18 throw std::runtime_error("Timer already initialized");
19 }
20
21 // Add infinite expiration time
22 auto r = sd_event_add_time(timeEvent, &eventSource,
23 CLOCK_MONOTONIC, // Time base
24 UINT64_MAX, // Expire time - way long time
25 0, // Use default event accuracy
26 timeoutHandler, // Callback handler on timeout
27 this); // User data
28 if (r < 0)
29 {
30 log<level::ERR>("Failure to set initial expiration time value",
Vernon Mauery9e801a22018-10-12 13:20:49 -070031 entry("ERROR=%s", strerror(-r)));
Ratan Gupta40801362018-03-12 16:21:37 +053032
33 throw std::runtime_error("Timer initialization failed");
34 }
35
36 // Disable the timer for now
37 r = setTimer(SD_EVENT_OFF);
38 if (r < 0)
39 {
40 log<level::ERR>("Failure to disable timer",
Vernon Mauery9e801a22018-10-12 13:20:49 -070041 entry("ERROR=%s", strerror(-r)));
Ratan Gupta40801362018-03-12 16:21:37 +053042
43 throw std::runtime_error("Disabling the timer failed");
44 }
45 return;
46}
47
48/** @brief callback handler on timeout */
Vernon Mauery9e801a22018-10-12 13:20:49 -070049int Timer::timeoutHandler(sd_event_source* eventSource, uint64_t usec,
50 void* userData)
Ratan Gupta40801362018-03-12 16:21:37 +053051{
52 auto timer = static_cast<Timer*>(userData);
53 timer->expired = true;
54
55 log<level::INFO>("Timer expired");
56 // Call optional user call back function if available
Vernon Mauery9e801a22018-10-12 13:20:49 -070057 if (timer->userCallBack)
Ratan Gupta40801362018-03-12 16:21:37 +053058 {
59 timer->userCallBack();
60 }
61
62 sd_event_source_set_enabled(eventSource, SD_EVENT_OFF);
63 return 0;
64}
65
66// Gets the time from steady_clock
67std::chrono::microseconds Timer::getTime()
68{
69 using namespace std::chrono;
70 auto usec = steady_clock::now().time_since_epoch();
71 return duration_cast<microseconds>(usec);
72}
73
74// Enables or disables the timer
75int Timer::setTimer(int action)
76{
77 return sd_event_source_set_enabled(eventSource, action);
78}
79
80// Sets the time and arms the timer
81int Timer::startTimer(std::chrono::microseconds timeValue)
82{
83 // Disable the timer
84 setTimer(SD_EVENT_OFF);
85 expired = false;
86
87 // Get the current MONOTONIC time and add the delta
88 auto expireTime = getTime() + timeValue;
89
90 // Set the time
91 auto r = sd_event_source_set_time(eventSource, expireTime.count());
92 if (r < 0)
93 {
94 log<level::ERR>("Failure to set timer",
Vernon Mauery9e801a22018-10-12 13:20:49 -070095 entry("ERROR=%s", strerror(-r)));
Ratan Gupta40801362018-03-12 16:21:37 +053096 return r;
97 }
98
99 // A ONESHOT timer means that when the timer goes off,
100 // its moves to disabled state.
101 r = setTimer(SD_EVENT_ONESHOT);
102 if (r < 0)
103 {
104 log<level::ERR>("Failure to start timer",
Vernon Mauery9e801a22018-10-12 13:20:49 -0700105 entry("ERROR=%s", strerror(-r)));
Ratan Gupta40801362018-03-12 16:21:37 +0530106 }
107 return r;
108}
109
110} // namespace ipmi
111} // namespace phosphor