1d2b00440SPatrick Williams #include <sys/eventfd.h>
229c4d435SPatrick Williams #include <unistd.h>
3d2b00440SPatrick Williams
4d2b00440SPatrick Williams #include <sdbusplus/event.hpp>
5d2b00440SPatrick Williams #include <sdbusplus/exception.hpp>
6d2b00440SPatrick Williams
7d2b00440SPatrick Williams namespace sdbusplus::event
8d2b00440SPatrick Williams {
9d2b00440SPatrick Williams
source(source && s)10d2b00440SPatrick Williams source::source(source&& s)
11d2b00440SPatrick Williams {
12d2b00440SPatrick Williams if (&s == this)
13d2b00440SPatrick Williams {
14d2b00440SPatrick Williams return;
15d2b00440SPatrick Williams }
16d2b00440SPatrick Williams ev = std::exchange(s.ev, nullptr);
17d2b00440SPatrick Williams sourcep = std::exchange(s.sourcep, nullptr);
18d2b00440SPatrick Williams }
19d2b00440SPatrick Williams
operator =(source && s)20d2b00440SPatrick Williams source& source::operator=(source&& s)
21d2b00440SPatrick Williams {
22d2b00440SPatrick Williams if (nullptr != sourcep)
23d2b00440SPatrick Williams {
24d2b00440SPatrick Williams auto l = ev->obtain_lock();
25d2b00440SPatrick Williams sd_event_source_unref(sourcep);
26d2b00440SPatrick Williams }
27d2b00440SPatrick Williams ev = std::exchange(s.ev, nullptr);
28d2b00440SPatrick Williams sourcep = std::exchange(s.sourcep, nullptr);
29d2b00440SPatrick Williams
30d2b00440SPatrick Williams return *this;
31d2b00440SPatrick Williams }
32d2b00440SPatrick Williams
~source()33d2b00440SPatrick Williams source::~source()
34d2b00440SPatrick Williams {
35d2b00440SPatrick Williams if (nullptr != sourcep)
36d2b00440SPatrick Williams {
37d2b00440SPatrick Williams auto l = ev->obtain_lock();
38d2b00440SPatrick Williams sd_event_source_unref(sourcep);
39d2b00440SPatrick Williams }
40d2b00440SPatrick Williams }
41d2b00440SPatrick Williams
condition(condition && c)42d2b00440SPatrick Williams condition::condition(condition&& c)
43d2b00440SPatrick Williams {
44d2b00440SPatrick Williams if (&c == this)
45d2b00440SPatrick Williams {
46d2b00440SPatrick Williams return;
47d2b00440SPatrick Williams }
48d2b00440SPatrick Williams
49d2b00440SPatrick Williams condition_source = std::move(c.condition_source);
50d2b00440SPatrick Williams fd = std::exchange(c.fd, -1);
51d2b00440SPatrick Williams }
52d2b00440SPatrick Williams
operator =(condition && c)53d2b00440SPatrick Williams condition& condition::operator=(condition&& c)
54d2b00440SPatrick Williams {
55d2b00440SPatrick Williams condition_source = std::move(c.condition_source);
56d2b00440SPatrick Williams if (fd >= 0)
57d2b00440SPatrick Williams {
58d2b00440SPatrick Williams close(fd);
59d2b00440SPatrick Williams }
60d2b00440SPatrick Williams fd = std::exchange(c.fd, -1);
61d2b00440SPatrick Williams
62d2b00440SPatrick Williams return *this;
63d2b00440SPatrick Williams }
64d2b00440SPatrick Williams
signal()65d2b00440SPatrick Williams void condition::signal()
66d2b00440SPatrick Williams {
67d2b00440SPatrick Williams uint64_t value = 1;
68d2b00440SPatrick Williams auto rc = write(fd, &value, sizeof(value));
69d2b00440SPatrick Williams if (rc < static_cast<decltype(rc)>(sizeof(value)))
70d2b00440SPatrick Williams {
71d2b00440SPatrick Williams throw exception::SdBusError(errno, __func__);
72d2b00440SPatrick Williams }
73d2b00440SPatrick Williams }
74d2b00440SPatrick Williams
ack()75d2b00440SPatrick Williams void condition::ack()
76d2b00440SPatrick Williams {
77d2b00440SPatrick Williams uint64_t value = 0;
78d2b00440SPatrick Williams auto rc = read(fd, &value, sizeof(value));
79d2b00440SPatrick Williams if (rc < static_cast<decltype(rc)>(sizeof(value)))
80d2b00440SPatrick Williams {
81d2b00440SPatrick Williams throw exception::SdBusError(errno, __func__);
82d2b00440SPatrick Williams }
83d2b00440SPatrick Williams }
84d2b00440SPatrick Williams
event()85d2b00440SPatrick Williams event::event()
86d2b00440SPatrick Williams {
87d2b00440SPatrick Williams if (auto rc = sd_event_new(&eventp); rc < 0)
88d2b00440SPatrick Williams {
89d2b00440SPatrick Williams throw exception::SdBusError(-rc, __func__);
90d2b00440SPatrick Williams }
91d2b00440SPatrick Williams run_condition = add_condition(run_wakeup, this);
92d2b00440SPatrick Williams }
93d2b00440SPatrick Williams
run_one(time_resolution timeout)94435eb1bdSPatrick Williams void event::run_one(time_resolution timeout)
95d2b00440SPatrick Williams {
96d2b00440SPatrick Williams auto l = obtain_lock<false>();
97d2b00440SPatrick Williams
98d2b00440SPatrick Williams auto rc = sd_event_run(eventp, static_cast<uint64_t>(timeout.count()));
99d2b00440SPatrick Williams if (rc < 0)
100d2b00440SPatrick Williams {
101d2b00440SPatrick Williams throw exception::SdBusError(-rc, __func__);
102d2b00440SPatrick Williams }
103d2b00440SPatrick Williams }
104d2b00440SPatrick Williams
break_run()105d2b00440SPatrick Williams void event::break_run()
106d2b00440SPatrick Williams {
107d2b00440SPatrick Williams run_condition.signal();
108d2b00440SPatrick Williams }
109d2b00440SPatrick Williams
add_io(int fd,uint32_t events,sd_event_io_handler_t handler,void * data)110d2b00440SPatrick Williams source event::add_io(int fd, uint32_t events, sd_event_io_handler_t handler,
111d2b00440SPatrick Williams void* data)
112d2b00440SPatrick Williams {
113d2b00440SPatrick Williams auto l = obtain_lock();
114d2b00440SPatrick Williams
115d2b00440SPatrick Williams source s{*this};
116d2b00440SPatrick Williams
117d2b00440SPatrick Williams auto rc = sd_event_add_io(eventp, &s.sourcep, fd, events, handler, data);
118d2b00440SPatrick Williams if (rc < 0)
119d2b00440SPatrick Williams {
120d2b00440SPatrick Williams throw exception::SdBusError(-rc, __func__);
121d2b00440SPatrick Williams }
122d2b00440SPatrick Williams
123d2b00440SPatrick Williams return s;
124d2b00440SPatrick Williams }
125d2b00440SPatrick Williams
add_condition(sd_event_io_handler_t handler,void * data)126d2b00440SPatrick Williams condition event::add_condition(sd_event_io_handler_t handler, void* data)
127d2b00440SPatrick Williams {
128d2b00440SPatrick Williams // We don't need any locks here because we only touch the sd_event
129d2b00440SPatrick Williams // indirectly through `add_io` which handles its own locking.
130d2b00440SPatrick Williams
131d2b00440SPatrick Williams auto fd = eventfd(0, 0);
132d2b00440SPatrick Williams if (fd < 0)
133d2b00440SPatrick Williams {
134d2b00440SPatrick Williams throw exception::SdBusError(errno, __func__);
135d2b00440SPatrick Williams }
136d2b00440SPatrick Williams
137d2b00440SPatrick Williams try
138d2b00440SPatrick Williams {
139d2b00440SPatrick Williams auto io = add_io(fd, EPOLLIN, handler, data);
140d2b00440SPatrick Williams return {std::move(io), std::move(fd)};
141d2b00440SPatrick Williams }
142d2b00440SPatrick Williams catch (...)
143d2b00440SPatrick Williams {
144d2b00440SPatrick Williams close(fd);
145d2b00440SPatrick Williams throw;
146d2b00440SPatrick Williams }
147d2b00440SPatrick Williams }
148d2b00440SPatrick Williams
add_oneshot_timer(sd_event_time_handler_t handler,void * data,time_resolution time,time_resolution accuracy)1493ce3159bSPatrick Williams source event::add_oneshot_timer(sd_event_time_handler_t handler, void* data,
150435eb1bdSPatrick Williams time_resolution time, time_resolution accuracy)
1513ce3159bSPatrick Williams {
1523ce3159bSPatrick Williams auto l = obtain_lock();
1533ce3159bSPatrick Williams
1543ce3159bSPatrick Williams source s{*this};
1553ce3159bSPatrick Williams
156*06f265f6SPatrick Williams auto rc = sd_event_add_time_relative(
157*06f265f6SPatrick Williams eventp, &s.sourcep, CLOCK_BOOTTIME, time.count(), accuracy.count(),
1583ce3159bSPatrick Williams handler, data);
1593ce3159bSPatrick Williams
1603ce3159bSPatrick Williams if (rc < 0)
1613ce3159bSPatrick Williams {
1623ce3159bSPatrick Williams throw exception::SdBusError(-rc, __func__);
1633ce3159bSPatrick Williams }
1643ce3159bSPatrick Williams
1653ce3159bSPatrick Williams return s;
1663ce3159bSPatrick Williams }
1673ce3159bSPatrick Williams
run_wakeup(sd_event_source *,int,uint32_t,void * data)168d2b00440SPatrick Williams int event::run_wakeup(sd_event_source*, int, uint32_t, void* data)
169d2b00440SPatrick Williams {
170d2b00440SPatrick Williams auto self = static_cast<event*>(data);
171d2b00440SPatrick Williams self->run_condition.ack();
172d2b00440SPatrick Williams
173d2b00440SPatrick Williams return 0;
174d2b00440SPatrick Williams }
175d2b00440SPatrick Williams
176d2b00440SPatrick Williams template <bool Signal>
obtain_lock()177d2b00440SPatrick Williams std::unique_lock<std::recursive_mutex> event::obtain_lock()
178d2b00440SPatrick Williams {
1795c50fc66SPatrick Williams std::unique_lock stage{this->obtain_lock_stage};
1805c50fc66SPatrick Williams
181d2b00440SPatrick Williams std::unique_lock<std::recursive_mutex> l{this->lock, std::defer_lock_t()};
182d2b00440SPatrick Williams if constexpr (Signal)
183d2b00440SPatrick Williams {
184d2b00440SPatrick Williams if (!l.try_lock())
185d2b00440SPatrick Williams {
186d2b00440SPatrick Williams run_condition.signal();
187d2b00440SPatrick Williams l.lock();
188d2b00440SPatrick Williams }
189d2b00440SPatrick Williams }
190d2b00440SPatrick Williams else
191d2b00440SPatrick Williams {
192d2b00440SPatrick Williams l.lock();
193d2b00440SPatrick Williams }
194d2b00440SPatrick Williams
195d2b00440SPatrick Williams return l;
196d2b00440SPatrick Williams }
197d2b00440SPatrick Williams
198d2b00440SPatrick Williams } // namespace sdbusplus::event
199