xref: /openbmc/sdbusplus/src/event.cpp (revision 06f265f6f18e22b1fb68761edb50ecd6722c2a47)
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