xref: /openbmc/sdbusplus/src/event.cpp (revision f7944dcb)
1 #include <sys/eventfd.h>
2 
3 #include <sdbusplus/event.hpp>
4 #include <sdbusplus/exception.hpp>
5 
6 namespace sdbusplus::event
7 {
8 
9 source::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 
19 source& 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 
32 source::~source()
33 {
34     if (nullptr != sourcep)
35     {
36         auto l = ev->obtain_lock();
37         sd_event_source_unref(sourcep);
38     }
39 }
40 
41 condition::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 
52 condition& 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 
64 void 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 
74 void 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 
84 event::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 
93 void event::run_one(time_resolution 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 
104 void event::break_run()
105 {
106     run_condition.signal();
107 }
108 
109 source 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 
125 condition 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 
148 source event::add_oneshot_timer(sd_event_time_handler_t handler, void* data,
149                                 time_resolution time, time_resolution accuracy)
150 {
151     auto l = obtain_lock();
152 
153     source s{*this};
154 
155     auto rc = sd_event_add_time_relative(eventp, &s.sourcep, CLOCK_BOOTTIME,
156                                          time.count(), accuracy.count(),
157                                          handler, data);
158 
159     if (rc < 0)
160     {
161         throw exception::SdBusError(-rc, __func__);
162     }
163 
164     return s;
165 }
166 
167 int event::run_wakeup(sd_event_source*, int, uint32_t, void* data)
168 {
169     auto self = static_cast<event*>(data);
170     self->run_condition.ack();
171 
172     return 0;
173 }
174 
175 template <bool Signal>
176 std::unique_lock<std::recursive_mutex> event::obtain_lock()
177 {
178     std::unique_lock<std::recursive_mutex> l{this->lock, std::defer_lock_t()};
179     if constexpr (Signal)
180     {
181         if (!l.try_lock())
182         {
183             run_condition.signal();
184             l.lock();
185         }
186     }
187     else
188     {
189         l.lock();
190     }
191 
192     return l;
193 }
194 
195 } // namespace sdbusplus::event
196