1 /*
2 * SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 */
7
8 #include <exception>
9 #include <functional>
10 #include <mutex>
11
12 #if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
13 #define __INCLUDE_LEVEL__ 2
14 #endif
15 #include <systemd/sd-event.h>
16 #include "event.h"
17 #include "log.h"
18
19 namespace fcitx {
20
IOEventFlagsToEpollFlags(IOEventFlags flags)21 static uint32_t IOEventFlagsToEpollFlags(IOEventFlags flags) {
22 uint32_t result = 0;
23 if (flags & IOEventFlag::In) {
24 result |= EPOLLIN;
25 }
26 if (flags & IOEventFlag::Out) {
27 result |= EPOLLOUT;
28 }
29 if (flags & IOEventFlag::Err) {
30 result |= EPOLLERR;
31 }
32 if (flags & IOEventFlag::Hup) {
33 result |= EPOLLHUP;
34 }
35 if (flags & IOEventFlag::EdgeTrigger) {
36 result |= EPOLLET;
37 }
38 return result;
39 }
40
EpollFlagsToIOEventFlags(uint32_t flags)41 static IOEventFlags EpollFlagsToIOEventFlags(uint32_t flags) {
42 return ((flags & EPOLLIN) ? IOEventFlag::In : IOEventFlags()) |
43 ((flags & EPOLLOUT) ? IOEventFlag::Out : IOEventFlags()) |
44 ((flags & EPOLLERR) ? IOEventFlag::Err : IOEventFlags()) |
45 ((flags & EPOLLHUP) ? IOEventFlag::Hup : IOEventFlags()) |
46 ((flags & EPOLLET) ? IOEventFlag::EdgeTrigger : IOEventFlags());
47 }
48
49 template <typename Interface>
50 struct SDEventSourceBase : public Interface {
51 public:
~SDEventSourceBasefcitx::SDEventSourceBase52 ~SDEventSourceBase() {
53 if (eventSource_) {
54 sd_event_source_set_enabled(eventSource_, SD_EVENT_OFF);
55 sd_event_source_set_userdata(eventSource_, nullptr);
56 sd_event_source_unref(eventSource_);
57 }
58 }
59
setEventSourcefcitx::SDEventSourceBase60 void setEventSource(sd_event_source *event) { eventSource_ = event; }
61
isEnabledfcitx::SDEventSourceBase62 bool isEnabled() const override {
63 int result = 0, err;
64 if ((err = sd_event_source_get_enabled(eventSource_, &result)) < 0) {
65 throw EventLoopException(err);
66 }
67 return result != SD_EVENT_OFF;
68 }
69
setEnabledfcitx::SDEventSourceBase70 void setEnabled(bool enabled) override {
71 sd_event_source_set_enabled(eventSource_,
72 enabled ? SD_EVENT_ON : SD_EVENT_OFF);
73 }
74
isOneShotfcitx::SDEventSourceBase75 bool isOneShot() const override {
76 int result = 0, err;
77 if ((err = sd_event_source_get_enabled(eventSource_, &result)) < 0) {
78 throw EventLoopException(err);
79 }
80 return result == SD_EVENT_ONESHOT;
81 }
82
setOneShotfcitx::SDEventSourceBase83 void setOneShot() override {
84 sd_event_source_set_enabled(eventSource_, SD_EVENT_ONESHOT);
85 }
86
87 protected:
88 sd_event_source *eventSource_;
89 };
90
91 struct SDEventSource : public SDEventSourceBase<EventSource> {
SDEventSourcefcitx::SDEventSource92 SDEventSource(EventCallback _callback) : callback_(std::move(_callback)) {}
93
94 EventCallback callback_;
95 };
96
97 struct SDEventSourceIO : public SDEventSourceBase<EventSourceIO> {
SDEventSourceIOfcitx::SDEventSourceIO98 SDEventSourceIO(IOCallback _callback) : callback_(std::move(_callback)) {}
99
fdfcitx::SDEventSourceIO100 int fd() const override {
101 int ret = sd_event_source_get_io_fd(eventSource_);
102 if (ret < 0) {
103 throw EventLoopException(ret);
104 }
105 return ret;
106 }
107
setFdfcitx::SDEventSourceIO108 void setFd(int fd) override {
109 int ret = sd_event_source_set_io_fd(eventSource_, fd);
110 if (ret < 0) {
111 throw EventLoopException(ret);
112 }
113 }
114
eventsfcitx::SDEventSourceIO115 IOEventFlags events() const override {
116 uint32_t events;
117 int ret = sd_event_source_get_io_events(eventSource_, &events);
118 if (ret < 0) {
119 throw EventLoopException(ret);
120 }
121 return EpollFlagsToIOEventFlags(events);
122 }
123
setEventsfcitx::SDEventSourceIO124 void setEvents(IOEventFlags flags) override {
125 int ret = sd_event_source_set_io_events(
126 eventSource_, IOEventFlagsToEpollFlags(flags));
127 if (ret < 0) {
128 throw EventLoopException(ret);
129 }
130 }
131
reventsfcitx::SDEventSourceIO132 IOEventFlags revents() const override {
133 uint32_t revents;
134 int ret = sd_event_source_get_io_revents(eventSource_, &revents);
135 if (ret < 0) {
136 throw EventLoopException(ret);
137 }
138 return EpollFlagsToIOEventFlags(revents);
139 }
140
141 IOCallback callback_;
142 };
143
144 struct SDEventSourceTime : public SDEventSourceBase<EventSourceTime> {
SDEventSourceTimefcitx::SDEventSourceTime145 SDEventSourceTime(TimeCallback _callback)
146 : callback_(std::move(_callback)) {}
147
timefcitx::SDEventSourceTime148 uint64_t time() const override {
149 uint64_t time;
150 int err = sd_event_source_get_time(eventSource_, &time);
151 if (err < 0) {
152 throw EventLoopException(err);
153 }
154 return time;
155 }
156
setTimefcitx::SDEventSourceTime157 void setTime(uint64_t time) override {
158 int ret = sd_event_source_set_time(eventSource_, time);
159 if (ret < 0) {
160 throw EventLoopException(ret);
161 }
162 }
163
accuracyfcitx::SDEventSourceTime164 uint64_t accuracy() const override {
165 uint64_t time;
166 int err = sd_event_source_get_time_accuracy(eventSource_, &time);
167 if (err < 0) {
168 throw EventLoopException(err);
169 }
170 return time;
171 }
172
setAccuracyfcitx::SDEventSourceTime173 void setAccuracy(uint64_t time) override {
174 int ret = sd_event_source_set_time_accuracy(eventSource_, time);
175 if (ret < 0) {
176 throw EventLoopException(ret);
177 }
178 }
179
clockfcitx::SDEventSourceTime180 clockid_t clock() const override {
181 clockid_t clock;
182 int err = sd_event_source_get_time_clock(eventSource_, &clock);
183 if (err < 0) {
184 throw EventLoopException(err);
185 }
186 return clock;
187 }
188
189 TimeCallback callback_;
190 };
191
192 class EventLoopPrivate {
193 public:
EventLoopPrivate()194 EventLoopPrivate() {
195 if (sd_event_new(&event_) < 0) {
196 throw std::runtime_error("Create sd_event failed.");
197 }
198 }
199
~EventLoopPrivate()200 ~EventLoopPrivate() { sd_event_unref(event_); }
201
202 std::mutex mutex_;
203 sd_event *event_;
204 };
205
EventLoop()206 EventLoop::EventLoop() : d_ptr(std::make_unique<EventLoopPrivate>()) {}
207
~EventLoop()208 EventLoop::~EventLoop() {}
209
impl()210 const char *EventLoop::impl() { return "sd-event"; }
211
nativeHandle()212 void *EventLoop::nativeHandle() {
213 FCITX_D();
214 return d->event_;
215 }
216
exec()217 bool EventLoop::exec() {
218 FCITX_D();
219 int r = sd_event_loop(d->event_);
220 return r >= 0;
221 }
222
exit()223 void EventLoop::exit() {
224 FCITX_D();
225 sd_event_exit(d->event_, 0);
226 }
227
IOEventCallback(sd_event_source *,int fd,uint32_t revents,void * userdata)228 int IOEventCallback(sd_event_source *, int fd, uint32_t revents,
229 void *userdata) {
230 auto *source = static_cast<SDEventSourceIO *>(userdata);
231 if (!source) {
232 return 0;
233 }
234 try {
235 auto result =
236 source->callback_(source, fd, EpollFlagsToIOEventFlags(revents));
237 return result ? 0 : -1;
238 } catch (const std::exception &e) {
239 FCITX_FATAL() << e.what();
240 }
241 return -1;
242 }
243
addIOEvent(int fd,IOEventFlags flags,IOCallback callback)244 std::unique_ptr<EventSourceIO> EventLoop::addIOEvent(int fd, IOEventFlags flags,
245 IOCallback callback) {
246 FCITX_D();
247 auto source = std::make_unique<SDEventSourceIO>(std::move(callback));
248 sd_event_source *sdEventSource;
249 int err;
250 if ((err = sd_event_add_io(d->event_, &sdEventSource, fd,
251 IOEventFlagsToEpollFlags(flags), IOEventCallback,
252 source.get())) < 0) {
253 throw EventLoopException(err);
254 }
255 source->setEventSource(sdEventSource);
256 return source;
257 }
258
TimeEventCallback(sd_event_source *,uint64_t usec,void * userdata)259 int TimeEventCallback(sd_event_source *, uint64_t usec, void *userdata) {
260 auto *source = static_cast<SDEventSourceTime *>(userdata);
261 if (!source) {
262 return 0;
263 }
264 try {
265 auto result = source->callback_(source, usec);
266 return result ? 0 : -1;
267 } catch (const std::exception &e) {
268 // some abnormal things threw
269 FCITX_ERROR() << e.what();
270 abort();
271 }
272 return -1;
273 }
274
275 std::unique_ptr<EventSourceTime>
addTimeEvent(clockid_t clock,uint64_t usec,uint64_t accuracy,TimeCallback callback)276 EventLoop::addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy,
277 TimeCallback callback) {
278 FCITX_D();
279 auto source = std::make_unique<SDEventSourceTime>(std::move(callback));
280 sd_event_source *sdEventSource;
281 int err;
282 if ((err = sd_event_add_time(d->event_, &sdEventSource, clock, usec,
283 accuracy, TimeEventCallback, source.get())) <
284 0) {
285 throw EventLoopException(err);
286 }
287 source->setEventSource(sdEventSource);
288 return source;
289 }
290
StaticEventCallback(sd_event_source *,void * userdata)291 int StaticEventCallback(sd_event_source *, void *userdata) {
292 auto *source = static_cast<SDEventSource *>(userdata);
293 if (!source) {
294 return 0;
295 }
296 try {
297 auto result = source->callback_(source);
298 return result ? 0 : -1;
299 } catch (const std::exception &e) {
300 // some abnormal things threw
301 FCITX_ERROR() << e.what();
302 abort();
303 }
304 return -1;
305 }
306
addExitEvent(EventCallback callback)307 std::unique_ptr<EventSource> EventLoop::addExitEvent(EventCallback callback) {
308 FCITX_D();
309 auto source = std::make_unique<SDEventSource>(std::move(callback));
310 sd_event_source *sdEventSource;
311 int err;
312 if ((err = sd_event_add_exit(d->event_, &sdEventSource, StaticEventCallback,
313 source.get())) < 0) {
314 throw EventLoopException(err);
315 }
316 source->setEventSource(sdEventSource);
317 return source;
318 }
319
addDeferEvent(EventCallback callback)320 std::unique_ptr<EventSource> EventLoop::addDeferEvent(EventCallback callback) {
321 FCITX_D();
322 auto source = std::make_unique<SDEventSource>(std::move(callback));
323 sd_event_source *sdEventSource;
324 int err;
325 if ((err = sd_event_add_defer(d->event_, &sdEventSource,
326 StaticEventCallback, source.get())) < 0) {
327 throw EventLoopException(err);
328 }
329 source->setEventSource(sdEventSource);
330 return source;
331 }
332 } // namespace fcitx
333