blob: e9c11af55924113a36bf78c5298803a38d1c7dfd [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
93void event::run_one(std::chrono::microseconds timeout)
94{
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
148int event::run_wakeup(sd_event_source*, int, uint32_t, void* data)
149{
150 auto self = static_cast<event*>(data);
151 self->run_condition.ack();
152
153 return 0;
154}
155
156template <bool Signal>
157std::unique_lock<std::recursive_mutex> event::obtain_lock()
158{
159 std::unique_lock<std::recursive_mutex> l{this->lock, std::defer_lock_t()};
160 if constexpr (Signal)
161 {
162 if (!l.try_lock())
163 {
164 run_condition.signal();
165 l.lock();
166 }
167 }
168 else
169 {
170 l.lock();
171 }
172
173 return l;
174}
175
176} // namespace sdbusplus::event