blob: badd43a013a1bff77b83d3606045f2541f09cada [file] [log] [blame]
Patrick Williamsd2b00442022-09-16 08:28:07 -05001#include <sys/eventfd.h>
2
3#include <sdbusplus/event.hpp>
4#include <sdbusplus/exception.hpp>
5
6namespace sdbusplus::event
7{
8
9source::source(source&& s)
10{
11 if (&s == this)
12 {
13 return;
14 }
15 ev = std::exchange(s.ev, nullptr);
16 sourcep = std::exchange(s.sourcep, nullptr);
17}
18
19source& source::operator=(source&& s)
20{
21 if (nullptr != sourcep)
22 {
23 auto l = ev->obtain_lock();
24 sd_event_source_unref(sourcep);
25 }
26 ev = std::exchange(s.ev, nullptr);
27 sourcep = std::exchange(s.sourcep, nullptr);
28
29 return *this;
30}
31
32source::~source()
33{
34 if (nullptr != sourcep)
35 {
36 auto l = ev->obtain_lock();
37 sd_event_source_unref(sourcep);
38 }
39}
40
41condition::condition(condition&& c)
42{
43 if (&c == this)
44 {
45 return;
46 }
47
48 condition_source = std::move(c.condition_source);
49 fd = std::exchange(c.fd, -1);
50}
51
52condition& condition::operator=(condition&& c)
53{
54 condition_source = std::move(c.condition_source);
55 if (fd >= 0)
56 {
57 close(fd);
58 }
59 fd = std::exchange(c.fd, -1);
60
61 return *this;
62}
63
64void condition::signal()
65{
66 uint64_t value = 1;
67 auto rc = write(fd, &value, sizeof(value));
68 if (rc < static_cast<decltype(rc)>(sizeof(value)))
69 {
70 throw exception::SdBusError(errno, __func__);
71 }
72}
73
74void condition::ack()
75{
76 uint64_t value = 0;
77 auto rc = read(fd, &value, sizeof(value));
78 if (rc < static_cast<decltype(rc)>(sizeof(value)))
79 {
80 throw exception::SdBusError(errno, __func__);
81 }
82}
83
84event::event()
85{
86 if (auto rc = sd_event_new(&eventp); rc < 0)
87 {
88 throw exception::SdBusError(-rc, __func__);
89 }
90 run_condition = add_condition(run_wakeup, this);
91}
92
Patrick Williams435eb1b2022-09-16 16:22:07 -050093void event::run_one(time_resolution timeout)
Patrick Williamsd2b00442022-09-16 08:28:07 -050094{
95 auto l = obtain_lock<false>();
96
97 auto rc = sd_event_run(eventp, static_cast<uint64_t>(timeout.count()));
98 if (rc < 0)
99 {
100 throw exception::SdBusError(-rc, __func__);
101 }
102}
103
104void event::break_run()
105{
106 run_condition.signal();
107}
108
109source event::add_io(int fd, uint32_t events, sd_event_io_handler_t handler,
110 void* data)
111{
112 auto l = obtain_lock();
113
114 source s{*this};
115
116 auto rc = sd_event_add_io(eventp, &s.sourcep, fd, events, handler, data);
117 if (rc < 0)
118 {
119 throw exception::SdBusError(-rc, __func__);
120 }
121
122 return s;
123}
124
125condition event::add_condition(sd_event_io_handler_t handler, void* data)
126{
127 // We don't need any locks here because we only touch the sd_event
128 // indirectly through `add_io` which handles its own locking.
129
130 auto fd = eventfd(0, 0);
131 if (fd < 0)
132 {
133 throw exception::SdBusError(errno, __func__);
134 }
135
136 try
137 {
138 auto io = add_io(fd, EPOLLIN, handler, data);
139 return {std::move(io), std::move(fd)};
140 }
141 catch (...)
142 {
143 close(fd);
144 throw;
145 }
146}
147
Patrick Williams3ce31592022-09-16 14:05:56 -0500148source event::add_oneshot_timer(sd_event_time_handler_t handler, void* data,
Patrick Williams435eb1b2022-09-16 16:22:07 -0500149 time_resolution time, time_resolution accuracy)
Patrick Williams3ce31592022-09-16 14:05:56 -0500150{
151 auto l = obtain_lock();
152
153 source s{*this};
154
155 auto rc = sd_event_add_time_relative(eventp, &s.sourcep, CLOCK_BOOTTIME,
156 time.count(), accuracy.count(),
157 handler, data);
158
159 if (rc < 0)
160 {
161 throw exception::SdBusError(-rc, __func__);
162 }
163
164 return s;
165}
166
Patrick Williamsd2b00442022-09-16 08:28:07 -0500167int event::run_wakeup(sd_event_source*, int, uint32_t, void* data)
168{
169 auto self = static_cast<event*>(data);
170 self->run_condition.ack();
171
172 return 0;
173}
174
175template <bool Signal>
176std::unique_lock<std::recursive_mutex> event::obtain_lock()
177{
178 std::unique_lock<std::recursive_mutex> l{this->lock, std::defer_lock_t()};
179 if constexpr (Signal)
180 {
181 if (!l.try_lock())
182 {
183 run_condition.signal();
184 l.lock();
185 }
186 }
187 else
188 {
189 l.lock();
190 }
191
192 return l;
193}
194
195} // namespace sdbusplus::event