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