Fcitx
event_sdevent.cpp
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 <cstdint>
9 #include <cstdlib>
10 #include <exception>
11 #include <functional>
12 #include <memory>
13 #include <mutex>
14 #include <stdexcept>
15 #include <utility>
16 #include <sys/epoll.h>
17 #include "eventloopinterface.h"
18 #include "log.h"
19 #include "macros.h"
20 #include "misc_p.h"
21 #include "stringutils.h"
22 #include "unixfd.h"
23 
24 #if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
25 #define __INCLUDE_LEVEL__ 2
26 #endif
27 #include <systemd/sd-event.h>
28 
29 namespace fcitx {
30 
31 namespace {
32 uint32_t IOEventFlagsToEpollFlags(IOEventFlags flags) {
33  uint32_t result = 0;
34  if (flags & IOEventFlag::In) {
35  result |= EPOLLIN;
36  }
37  if (flags & IOEventFlag::Out) {
38  result |= EPOLLOUT;
39  }
40  if (flags & IOEventFlag::Err) {
41  result |= EPOLLERR;
42  }
43  if (flags & IOEventFlag::Hup) {
44  result |= EPOLLHUP;
45  }
46  if (flags & IOEventFlag::EdgeTrigger) {
47  result |= EPOLLET;
48  }
49  return result;
50 }
51 
52 IOEventFlags EpollFlagsToIOEventFlags(uint32_t flags) {
53  return ((flags & EPOLLIN) ? IOEventFlag::In : IOEventFlags()) |
54  ((flags & EPOLLOUT) ? IOEventFlag::Out : IOEventFlags()) |
55  ((flags & EPOLLERR) ? IOEventFlag::Err : IOEventFlags()) |
56  ((flags & EPOLLHUP) ? IOEventFlag::Hup : IOEventFlags()) |
57  ((flags & EPOLLET) ? IOEventFlag::EdgeTrigger : IOEventFlags());
58 }
59 
60 } // namespace
61 
63 public:
66  bool exec() override;
67  void exit() override;
68  const char *implementation() const override;
69  void *nativeHandle() override;
70 
71  FCITX_NODISCARD std::unique_ptr<EventSourceIO>
72  addIOEvent(int fd, IOEventFlags flags, IOCallback callback) override;
73  FCITX_NODISCARD std::unique_ptr<EventSourceTime>
74  addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy,
75  TimeCallback callback) override;
76  FCITX_NODISCARD std::unique_ptr<EventSource>
77  addExitEvent(EventCallback callback) override;
78  FCITX_NODISCARD std::unique_ptr<EventSource>
79  addDeferEvent(EventCallback callback) override;
80  FCITX_NODISCARD std::unique_ptr<EventSource>
81  addPostEvent(EventCallback callback) override;
82  FCITX_NODISCARD std::unique_ptr<EventSourceAsync>
83  addAsyncEvent(EventCallback callback) override;
84 
85 private:
86  std::mutex mutex_;
87  sd_event *event_ = nullptr;
88 };
89 
90 std::unique_ptr<EventLoopInterface> createDefaultEventLoop() {
91  return std::make_unique<EventLoopSDEvent>();
92 }
93 
94 const char *defaultEventLoopImplementation() { return "sd-event"; }
95 
96 template <typename Interface>
97 struct SDEventSourceBase : public Interface {
98 public:
99  ~SDEventSourceBase() override {
100  if (eventSource_) {
101  sd_event_source_set_enabled(eventSource_, SD_EVENT_OFF);
102  sd_event_source_set_userdata(eventSource_, nullptr);
103  sd_event_source_unref(eventSource_);
104  }
105  }
106 
107  void setEventSource(sd_event_source *event) { eventSource_ = event; }
108 
109  bool isEnabled() const override {
110  int result = 0;
111  if (int err = sd_event_source_get_enabled(eventSource_, &result);
112  err < 0) {
113  throw EventLoopException(err);
114  }
115  return result != SD_EVENT_OFF;
116  }
117 
118  void setEnabled(bool enabled) override {
119  sd_event_source_set_enabled(eventSource_,
120  enabled ? SD_EVENT_ON : SD_EVENT_OFF);
121  }
122 
123  bool isOneShot() const override {
124  int result = 0;
125  if (int err = sd_event_source_get_enabled(eventSource_, &result);
126  err < 0) {
127  throw EventLoopException(err);
128  }
129  return result == SD_EVENT_ONESHOT;
130  }
131 
132  void setOneShot() override {
133  sd_event_source_set_enabled(eventSource_, SD_EVENT_ONESHOT);
134  }
135 
136 protected:
137  sd_event_source *eventSource_;
138 };
139 
140 struct SDEventSource : public SDEventSourceBase<EventSource> {
141  SDEventSource(EventCallback _callback)
142  : callback_(std::make_shared<EventCallback>(std::move(_callback))) {}
143 
144  std::shared_ptr<EventCallback> callback_;
145 };
146 
147 struct SDEventSourceIO : public SDEventSourceBase<EventSourceIO> {
148  SDEventSourceIO(IOCallback _callback)
149  : callback_(std::make_shared<IOCallback>(std::move(_callback))) {}
150 
151  int fd() const override {
152  int ret = sd_event_source_get_io_fd(eventSource_);
153  if (ret < 0) {
154  throw EventLoopException(ret);
155  }
156  return ret;
157  }
158 
159  void setFd(int fd) override {
160  int ret = sd_event_source_set_io_fd(eventSource_, fd);
161  if (ret < 0) {
162  throw EventLoopException(ret);
163  }
164  }
165 
166  IOEventFlags events() const override {
167  uint32_t events;
168  int ret = sd_event_source_get_io_events(eventSource_, &events);
169  if (ret < 0) {
170  throw EventLoopException(ret);
171  }
172  return EpollFlagsToIOEventFlags(events);
173  }
174 
175  void setEvents(IOEventFlags flags) override {
176  int ret = sd_event_source_set_io_events(
177  eventSource_, IOEventFlagsToEpollFlags(flags));
178  if (ret < 0) {
179  throw EventLoopException(ret);
180  }
181  }
182 
183  IOEventFlags revents() const override {
184  uint32_t revents;
185  int ret = sd_event_source_get_io_revents(eventSource_, &revents);
186  if (ret < 0) {
187  throw EventLoopException(ret);
188  }
189  return EpollFlagsToIOEventFlags(revents);
190  }
191 
192  std::shared_ptr<IOCallback> callback_;
193 };
194 
195 struct SDEventSourceTime : public SDEventSourceBase<EventSourceTime> {
196  SDEventSourceTime(TimeCallback _callback)
197  : callback_(std::make_shared<TimeCallback>(std::move(_callback))) {}
198 
199  uint64_t time() const override {
200  uint64_t time;
201  int err = sd_event_source_get_time(eventSource_, &time);
202  if (err < 0) {
203  throw EventLoopException(err);
204  }
205  return time;
206  }
207 
208  void setTime(uint64_t time) override {
209  int ret = sd_event_source_set_time(eventSource_, time);
210  if (ret < 0) {
211  throw EventLoopException(ret);
212  }
213  }
214 
215  uint64_t accuracy() const override {
216  uint64_t time;
217  int err = sd_event_source_get_time_accuracy(eventSource_, &time);
218  if (err < 0) {
219  throw EventLoopException(err);
220  }
221  return time;
222  }
223 
224  void setAccuracy(uint64_t time) override {
225  int ret = sd_event_source_set_time_accuracy(eventSource_, time);
226  if (ret < 0) {
227  throw EventLoopException(ret);
228  }
229  }
230 
231  clockid_t clock() const override {
232  clockid_t clock;
233  int err = sd_event_source_get_time_clock(eventSource_, &clock);
234  if (err < 0) {
235  throw EventLoopException(err);
236  }
237  return clock;
238  }
239 
240  std::shared_ptr<TimeCallback> callback_;
241 };
242 
243 EventLoopSDEvent::EventLoopSDEvent() {
244  if (int rc = sd_event_new(&event_); rc < 0) {
245  throw std::runtime_error(
246  stringutils::concat("Create sd_event failed. error code: ", rc));
247  }
248 }
249 
250 EventLoopSDEvent::~EventLoopSDEvent() { sd_event_unref(event_); };
251 
252 const char *EventLoopSDEvent::implementation() const { return "sd-event"; }
253 
254 void *EventLoopSDEvent::nativeHandle() { return event_; }
255 
257  int r = sd_event_loop(event_);
258  return r >= 0;
259 }
260 
261 void EventLoopSDEvent::exit() { sd_event_exit(event_, 0); }
262 
263 int IOEventCallback(sd_event_source * /*unused*/, int fd, uint32_t revents,
264  void *userdata) {
265  auto *source = static_cast<SDEventSourceIO *>(userdata);
266  if (!source) {
267  return 0;
268  }
269  try {
270  auto callback = source->callback_;
271  auto result =
272  (*callback)(source, fd, EpollFlagsToIOEventFlags(revents));
273  return result ? 0 : -1;
274  } catch (const std::exception &e) {
275  FCITX_FATAL() << e.what();
276  }
277  return -1;
278 }
279 
280 std::unique_ptr<EventSourceIO>
281 EventLoopSDEvent::addIOEvent(int fd, IOEventFlags flags, IOCallback callback) {
282  auto source = std::make_unique<SDEventSourceIO>(std::move(callback));
283  sd_event_source *sdEventSource;
284  if (int err = sd_event_add_io(event_, &sdEventSource, fd,
285  IOEventFlagsToEpollFlags(flags),
286  IOEventCallback, source.get());
287  err < 0) {
288  throw EventLoopException(err);
289  }
290  source->setEventSource(sdEventSource);
291  return source;
292 }
293 
294 int TimeEventCallback(sd_event_source * /*unused*/, uint64_t usec,
295  void *userdata) {
296  auto *source = static_cast<SDEventSourceTime *>(userdata);
297  if (!source) {
298  return 0;
299  }
300  try {
301  auto callback = source->callback_;
302  auto result = (*callback)(source, usec);
303  return result ? 0 : -1;
304  } catch (const std::exception &e) {
305  // some abnormal things threw
306  FCITX_ERROR() << e.what();
307  std::abort();
308  }
309  return -1;
310 }
311 
312 std::unique_ptr<EventSourceTime>
313 EventLoopSDEvent::addTimeEvent(clockid_t clock, uint64_t usec,
314  uint64_t accuracy, TimeCallback callback) {
315  auto source = std::make_unique<SDEventSourceTime>(std::move(callback));
316  sd_event_source *sdEventSource;
317  if (int err = sd_event_add_time(event_, &sdEventSource, clock, usec,
318  accuracy, TimeEventCallback, source.get());
319  err < 0) {
320  throw EventLoopException(err);
321  }
322  source->setEventSource(sdEventSource);
323  return source;
324 }
325 
326 int StaticEventCallback(sd_event_source * /*unused*/, void *userdata) {
327  auto *source = static_cast<SDEventSource *>(userdata);
328  if (!source) {
329  return 0;
330  }
331  try {
332  auto callback = source->callback_;
333  auto result = (*callback)(source);
334  return result ? 0 : -1;
335  } catch (const std::exception &e) {
336  // some abnormal things threw
337  FCITX_ERROR() << e.what();
338  std::abort();
339  }
340  return -1;
341 }
342 
343 std::unique_ptr<EventSource>
344 EventLoopSDEvent::addExitEvent(EventCallback callback) {
345  auto source = std::make_unique<SDEventSource>(std::move(callback));
346  sd_event_source *sdEventSource;
347  if (int err = sd_event_add_exit(event_, &sdEventSource, StaticEventCallback,
348  source.get());
349  err < 0) {
350  throw EventLoopException(err);
351  }
352  source->setEventSource(sdEventSource);
353  return source;
354 }
355 
356 std::unique_ptr<EventSource>
357 EventLoopSDEvent::addDeferEvent(EventCallback callback) {
358  auto source = std::make_unique<SDEventSource>(std::move(callback));
359  sd_event_source *sdEventSource;
360  if (int err = sd_event_add_defer(event_, &sdEventSource,
361  StaticEventCallback, source.get());
362  err < 0) {
363  throw EventLoopException(err);
364  }
365  source->setEventSource(sdEventSource);
366  return source;
367 }
368 
369 std::unique_ptr<EventSource>
370 EventLoopSDEvent::addPostEvent(EventCallback callback) {
371  auto source = std::make_unique<SDEventSource>(std::move(callback));
372  sd_event_source *sdEventSource;
373  if (int err = sd_event_add_post(event_, &sdEventSource, StaticEventCallback,
374  source.get());
375  err < 0) {
376  throw EventLoopException(err);
377  }
378  source->setEventSource(sdEventSource);
379  return source;
380 }
381 
383 public:
384  SDEventSourceAsync(EventLoopInterfaceV2 *event, EventCallback callback) {
385  int selfpipe[2];
386  if (safePipe(selfpipe)) {
387  throw EventLoopException(-EPIPE);
388  }
389  fd_[0].give(selfpipe[0]);
390  fd_[1].give(selfpipe[1]);
391  ioEvent_ = event->addIOEvent(
392  fd_[0].fd(), IOEventFlag::In,
393  [this, callback = std::move(callback)](EventSource *, int fd,
394  IOEventFlags) {
395  uint8_t dummy;
396  while (fs::safeRead(fd, &dummy, sizeof(dummy)) > 0) {
397  }
398  callback(this);
399  return true;
400  });
401  }
402 
403  bool isEnabled() const override { return ioEvent_->isEnabled(); }
404  void setEnabled(bool enabled) override { ioEvent_->setEnabled(enabled); }
405  bool isOneShot() const override { return ioEvent_->isOneShot(); }
406  void setOneShot() override { ioEvent_->setOneShot(); }
407 
408  void send() override {
409  uint8_t dummy = 0;
410  fs::safeWrite(fd_[1].fd(), &dummy, 1);
411  }
412 
413 protected:
414  UnixFD fd_[2];
415  std::unique_ptr<EventSourceIO> ioEvent_;
416 };
417 
418 std::unique_ptr<EventSourceAsync>
419 EventLoopSDEvent::addAsyncEvent(EventCallback callback) {
420  return std::make_unique<SDEventSourceAsync>(this, std::move(callback));
421 }
422 
423 } // namespace fcitx
Class wrap around the unix fd.
Definition: unixfd.h:22
Definition: action.cpp:17
void send() override
Trigger the event from other thread.
Utility class to handle unix file decriptor.
void * nativeHandle() override
Return the internal native handle to the event loop.
A thread-safe event source can be triggered from other threads.
bool exec() override
Execute event loop.
ssize_t safeWrite(int fd, const void *data, size_t maxlen)
a simple wrapper around write(), ignore EINTR.
Definition: fs.cpp:238
const char * implementation() const override
Return a static implementation name of event loop.
String handle utilities.
ssize_t safeRead(int fd, void *data, size_t maxlen)
a simple wrapper around read(), ignore EINTR.
Definition: fs.cpp:231
Log utilities.
void exit() override
Quit event loop.