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