xref: /openbmc/sdbusplus/src/event.cpp (revision 5c50fc66)
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 
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 
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 
33 source::~source()
34 {
35     if (nullptr != sourcep)
36     {
37         auto l = ev->obtain_lock();
38         sd_event_source_unref(sourcep);
39     }
40 }
41 
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 
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 
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 
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 
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 
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 
105 void event::break_run()
106 {
107     run_condition.signal();
108 }
109 
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 
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 
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(eventp, &s.sourcep, CLOCK_BOOTTIME,
157                                          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 
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>
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