blob: 06965de1fc9ec7670b3c9ea22aab1b796fcb89f5 [file] [log] [blame]
Vishwanatha Subbannad27e71e2017-02-01 18:02:38 +05301#include <chrono>
Vishwanatha Subbannabcb76882017-01-25 16:29:43 +05302#include <phosphor-logging/log.hpp>
3#include "timer.hpp"
4namespace phosphor
5{
6namespace ipmi
7{
8
9using namespace phosphor::logging;
10
11// Initializes the timer object
12void Timer::initialize()
13{
14 // This can not be called more than once.
15 if (eventSource)
16 {
17 throw std::runtime_error("Timer already initialized");
18 }
19
20 // Add infinite expiration time
21 auto r = sd_event_add_time(timeEvent, &eventSource,
22 CLOCK_MONOTONIC, // Time base
Vishwanatha Subbannad27e71e2017-02-01 18:02:38 +053023 UINT64_MAX, // Expire time - way long time
Vishwanatha Subbannabcb76882017-01-25 16:29:43 +053024 0, // Use default event accuracy
25 timeoutHandler, // Callback handler on timeout
26 this); // User data
27 if (r < 0)
28 {
29 log<level::ERR>("Failure to set initial expiration time value",
30 entry("ERROR=%s", strerror(-r)));
31
32 throw std::runtime_error("Timer initialization failed");
33 }
34
35 // Disable the timer for now
Vishwanatha Subbannad27e71e2017-02-01 18:02:38 +053036 r = setTimer(SD_EVENT_OFF);
Vishwanatha Subbannabcb76882017-01-25 16:29:43 +053037 if (r < 0)
38 {
39 log<level::ERR>("Failure to disable timer",
40 entry("ERROR=%s", strerror(-r)));
41
Vishwanatha Subbannad27e71e2017-02-01 18:02:38 +053042 throw std::runtime_error("Disabling the timer failed");
Vishwanatha Subbannabcb76882017-01-25 16:29:43 +053043 }
44 return;
45}
46
47/** @brief callback handler on timeout */
48int Timer::timeoutHandler(sd_event_source* eventSource,
49 uint64_t usec, void* userData)
50{
51 auto timer = static_cast<Timer*>(userData);
52 timer->expired = true;
53
Ratan Gupta32cbd652018-03-07 16:03:53 +053054 log<level::INFO>("Timer expired");
Andrew Geissler8622f692017-04-02 18:19:00 -050055 // Call optional user call back function if available
56 if(timer->userCallBack)
57 {
58 timer->userCallBack();
59 }
60
Ratan Gupta32cbd652018-03-07 16:03:53 +053061 sd_event_source_set_enabled(eventSource, SD_EVENT_OFF);
Vishwanatha Subbannabcb76882017-01-25 16:29:43 +053062 return 0;
63}
64
Vishwanatha Subbannad27e71e2017-02-01 18:02:38 +053065// Gets the time from steady_clock
66std::chrono::microseconds Timer::getTime()
67{
68 using namespace std::chrono;
69 auto usec = steady_clock::now().time_since_epoch();
70 return duration_cast<microseconds>(usec);
71}
72
73// Enables or disables the timer
74int Timer::setTimer(int action)
75{
76 return sd_event_source_set_enabled(eventSource, action);
77}
78
79// Sets the time and arms the timer
80int Timer::startTimer(std::chrono::microseconds timeValue)
81{
82 // Disable the timer
83 setTimer(SD_EVENT_OFF);
Ratan Gupta32cbd652018-03-07 16:03:53 +053084 expired = false;
Vishwanatha Subbannad27e71e2017-02-01 18:02:38 +053085
86 // Get the current MONOTONIC time and add the delta
87 auto expireTime = getTime() + timeValue;
88
89 // Set the time
90 auto r = sd_event_source_set_time(eventSource, expireTime.count());
91 if (r < 0)
92 {
93 log<level::ERR>("Failure to set timer",
94 entry("ERROR=%s", strerror(-r)));
95 return r;
96 }
97
98 // A ONESHOT timer means that when the timer goes off,
99 // its moves to disabled state.
100 r = setTimer(SD_EVENT_ONESHOT);
101 if (r < 0)
102 {
103 log<level::ERR>("Failure to start timer",
104 entry("ERROR=%s", strerror(-r)));
105 }
106 return r;
107}
108
Vishwanatha Subbannabcb76882017-01-25 16:29:43 +0530109} // namespace ipmi
110} // namespace phosphor