1 #include <sys/eventfd.h>
2 #include <unistd.h>
3
4 #include <sdbusplus/event.hpp>
5 #include <sdbusplus/exception.hpp>
6
7 namespace sdbusplus::event
8 {
9
source(source && s)10 source::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
operator =(source && s)20 source& 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
~source()33 source::~source()
34 {
35 if (nullptr != sourcep)
36 {
37 auto l = ev->obtain_lock();
38 sd_event_source_unref(sourcep);
39 }
40 }
41
condition(condition && c)42 condition::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
operator =(condition && c)53 condition& 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
signal()65 void 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
ack()75 void 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
event()85 event::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
run_one(time_resolution timeout)94 void event::run_one(time_resolution timeout)
95 {
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
break_run()105 void event::break_run()
106 {
107 run_condition.signal();
108 }
109
add_io(int fd,uint32_t events,sd_event_io_handler_t handler,void * data)110 source 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
add_condition(sd_event_io_handler_t handler,void * data)126 condition 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
add_oneshot_timer(sd_event_time_handler_t handler,void * data,time_resolution time,time_resolution accuracy)149 source event::add_oneshot_timer(sd_event_time_handler_t handler, void* data,
150 time_resolution time, time_resolution accuracy)
151 {
152 auto l = obtain_lock();
153
154 source s{*this};
155
156 auto rc = sd_event_add_time_relative(
157 eventp, &s.sourcep, CLOCK_BOOTTIME, 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
run_wakeup(sd_event_source *,int,uint32_t,void * data)168 int 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
176 template <bool Signal>
obtain_lock()177 std::unique_lock<std::recursive_mutex> event::obtain_lock()
178 {
179 std::unique_lock stage{this->obtain_lock_stage};
180
181 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
199