blob: 2058462876abebf3718426b716b073b4eb15036c [file] [log] [blame]
Brad Bishop14631dc2017-06-14 22:34:03 -04001#pragma once
2
3#include <chrono>
4#include <memory>
Brad Bishopd516c612017-07-19 16:15:04 -04005#include <phosphor-logging/elog.hpp>
6#include <phosphor-logging/elog-errors.hpp>
Brad Bishop14631dc2017-06-14 22:34:03 -04007#include <sdbusplus/bus.hpp>
8#include <systemd/sd-event.h>
Brad Bishopd516c612017-07-19 16:15:04 -04009#include <xyz/openbmc_project/Common/error.hpp>
Brad Bishop14631dc2017-06-14 22:34:03 -040010
11namespace sdevent
12{
13namespace event
14{
Brad Bishope54a98f2017-06-14 23:10:37 -040015namespace io
16{
17class IO;
18} // namespace io
Brad Bishop14631dc2017-06-14 22:34:03 -040019
20using EventPtr = sd_event*;
21class Event;
22
23/** @brief Get an instance of the 'default' event. */
24Event newDefault();
25
26namespace details
27{
28
29/** @brief unique_ptr functor to release an event reference. */
30struct EventDeleter
31{
32 void operator()(sd_event* ptr) const
33 {
34 deleter(ptr);
35 }
36
37 decltype(&sd_event_unref) deleter = sd_event_unref;
38};
39
40/* @brief Alias 'event' to a unique_ptr type for auto-release. */
41using Event = std::unique_ptr<sd_event, EventDeleter>;
42
43} // namespace details
44
Marri Devender Rao60885582017-11-07 04:58:14 -060045using namespace phosphor::logging;
46
Brad Bishop14631dc2017-06-14 22:34:03 -040047/** @class Event
48 * @brief Provides C++ bindings to the sd_event_* class functions.
49 */
50class Event
51{
Brad Bishopd516c612017-07-19 16:15:04 -040052 private:
53 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
54 Error::InternalFailure;
55
Brad Bishop14631dc2017-06-14 22:34:03 -040056 public:
57 /* Define all of the basic class operations:
58 * Not allowed:
59 * - Default constructor to avoid nullptrs.
60 * - Copy operations due to internal unique_ptr.
61 * Allowed:
62 * - Move operations.
63 * - Destructor.
64 */
65 Event() = delete;
66 Event(const Event&) = delete;
67 Event& operator=(const Event&) = delete;
68 Event(Event&&) = default;
69 Event& operator=(Event&&) = default;
70 ~Event() = default;
71
72 /** @brief Conversion constructor from 'EventPtr'.
73 *
74 * Increments ref-count of the event-pointer and releases it when
75 * done.
76 */
77 explicit Event(EventPtr e);
78
79 /** @brief Constructor for 'Event'.
80 *
81 * Takes ownership of the event-pointer and releases it when done.
82 */
83 Event(EventPtr e, std::false_type);
84
85 /** @brief Release ownership of the stored event-pointer. */
86 EventPtr release()
87 {
88 return evt.release();
89 }
90
91 /** @brief Wait indefinitely for new event sources. */
92 void loop()
93 {
Brad Bishopd516c612017-07-19 16:15:04 -040094 auto rc = sd_event_loop(evt.get());
95 if (rc < 0)
96 {
Marri Devender Rao60885582017-11-07 04:58:14 -060097 log<level::ERR>("Error in call to sd_event_loop",
98 entry("RC=%d", rc));
99 elog<InternalFailure>();
Brad Bishopd516c612017-07-19 16:15:04 -0400100 }
Brad Bishop14631dc2017-06-14 22:34:03 -0400101 }
102
Brad Bishop0c9271f2017-06-15 22:30:15 -0400103 /** @brief Stop the loop. */
104 void exit(int status = 0)
105 {
106 auto rc = sd_event_exit(evt.get(), status);
107 if (rc < 0)
108 {
Marri Devender Rao60885582017-11-07 04:58:14 -0600109 log<level::ERR>("Error in call to sd_event_exit",
110 entry("RC=%d", rc),
111 entry("STATUS=%d", status));
112 elog<InternalFailure>();
Brad Bishop0c9271f2017-06-15 22:30:15 -0400113 }
114 }
115
116 /** @brief Get the loop exit code. */
117 auto getExitStatus()
118 {
119 int status;
120 auto rc = sd_event_get_exit_code(evt.get(), &status);
121 if (rc < 0)
122 {
Marri Devender Rao60885582017-11-07 04:58:14 -0600123 log<level::ERR>("Error in call to sd_event_get_exit_code",
124 entry("RC=%d", rc));
125 elog<InternalFailure>();
Brad Bishop0c9271f2017-06-15 22:30:15 -0400126 }
127
128 return status;
129 }
130
Brad Bishop14631dc2017-06-14 22:34:03 -0400131 /** @brief Attach to a DBus loop. */
132 void attach(sdbusplus::bus::bus& bus)
133 {
134 bus.attach_event(evt.get(), SD_EVENT_PRIORITY_NORMAL);
135 }
136
137 /** @brief C++ wrapper for sd_event_now. */
138 auto now()
139 {
140 using namespace std::chrono;
141
142 uint64_t usec;
Brad Bishopd516c612017-07-19 16:15:04 -0400143 auto rc = sd_event_now(evt.get(), CLOCK_MONOTONIC, &usec);
144 if (rc < 0)
145 {
Marri Devender Rao60885582017-11-07 04:58:14 -0600146 log<level::ERR>("Error in call to sd_event_now",
147 entry("RC=%d", rc));
148 elog<InternalFailure>();
Brad Bishopd516c612017-07-19 16:15:04 -0400149 }
150
Brad Bishop14631dc2017-06-14 22:34:03 -0400151 microseconds d(usec);
152 return steady_clock::time_point(d);
153 }
154
Brad Bishope54a98f2017-06-14 23:10:37 -0400155 friend class io::IO;
156
Brad Bishop14631dc2017-06-14 22:34:03 -0400157 private:
158
159 EventPtr get()
160 {
161 return evt.get();
162 }
163
164 details::Event evt;
165};
166
167inline Event::Event(EventPtr l) : evt(sd_event_ref(l))
168{
169
170}
171
172inline Event::Event(EventPtr l, std::false_type) : evt(l)
173{
174
175}
176
177inline Event newDefault()
178{
Brad Bishopd516c612017-07-19 16:15:04 -0400179 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
180 Error::InternalFailure;
181
Brad Bishop14631dc2017-06-14 22:34:03 -0400182 sd_event* e = nullptr;
Brad Bishopd516c612017-07-19 16:15:04 -0400183 auto rc = sd_event_default(&e);
184 if (rc < 0)
185 {
Marri Devender Rao60885582017-11-07 04:58:14 -0600186 log<level::ERR>("Error in call to sd_event_default",
187 entry("RC=%d", rc));
188 elog<InternalFailure>();
Brad Bishopd516c612017-07-19 16:15:04 -0400189 }
190
Brad Bishop14631dc2017-06-14 22:34:03 -0400191 return Event(e, std::false_type());
192}
193
194} // namespace event
195} // namespace sdevent