Fcitx
event_libuv.h
1 /*
2  * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_UTILS_EVENT_LIBUV_H_
8 #define _FCITX_UTILS_EVENT_LIBUV_H_
9 
10 #include <cstdint>
11 #include <cstdlib>
12 #include <memory>
13 #include <utility>
14 #include <vector>
15 #include <fcitx-utils/eventloopinterface.h>
16 #include <fcitx-utils/log.h>
17 #include <fcitx-utils/macros.h>
19 #include <uv.h>
20 
21 namespace fcitx {
22 
23 struct UVLoop {
24  UVLoop() { uv_loop_init(&loop_); }
25 
26  ~UVLoop();
27 
28  operator uv_loop_t *() { return &loop_; }
29 
30  uv_loop_t loop_;
31 };
32 
33 enum class LibUVSourceEnableState { Disabled = 0, Oneshot = 1, Enabled = 2 };
34 
36 public:
37  LibUVSourceBase(const std::shared_ptr<UVLoop> &loop) : loop_(loop) {}
38 
39  virtual ~LibUVSourceBase() { cleanup(); };
40  void cleanup() {
41  if (!handle_) {
42  return;
43  }
44  auto *handle = handle_;
45  handle_->data = nullptr;
46  handle_ = nullptr;
47  uv_close(handle, [](uv_handle_t *handle) { free(handle); });
48  }
49 
50  virtual void init(uv_loop_t *loop) = 0;
51 
52  void resetEvent() {
53  cleanup();
54  if (state_ == LibUVSourceEnableState::Disabled) {
55  return;
56  }
57  auto loop = loop_.lock();
58  if (!loop) {
59  return;
60  }
61  init(*loop);
62  }
63 
64 protected:
65  void setState(LibUVSourceEnableState state) {
66  if (state_ != state) {
67  state_ = state;
68  resetEvent();
69  }
70  }
71 
72  std::weak_ptr<UVLoop> loop_;
73  uv_handle_t *handle_ = nullptr;
74  LibUVSourceEnableState state_ = LibUVSourceEnableState::Disabled;
75 };
76 
77 template <typename Interface, typename HandleType>
78 struct LibUVSource : public Interface, public LibUVSourceBase {
79 public:
80  LibUVSource(std::shared_ptr<UVLoop> loop)
81  : LibUVSourceBase(std::move(loop)) {}
82 
83  bool isEnabled() const override {
84  return state_ != LibUVSourceEnableState::Disabled;
85  }
86  void setEnabled(bool enabled) override {
87  auto newState = enabled ? LibUVSourceEnableState::Enabled
88  : LibUVSourceEnableState::Disabled;
89  setState(newState);
90  }
91 
92  void setOneShot() override { setState(LibUVSourceEnableState::Oneshot); }
93 
94  bool isOneShot() const override {
95  return state_ == LibUVSourceEnableState::Oneshot;
96  }
97 
98  inline HandleType *handle() {
99  return reinterpret_cast<HandleType *>(handle_);
100  }
101 
102  void init(uv_loop_t *loop) override {
103  handle_ = static_cast<uv_handle_t *>(calloc(1, sizeof(HandleType)));
104  handle_->data = static_cast<LibUVSourceBase *>(this);
105  if (!setup(loop, handle())) {
106  free(handle_);
107  handle_ = nullptr;
108  }
109  }
110 
111  virtual bool setup(uv_loop_t *loop, HandleType *handle) = 0;
112 };
113 
114 struct LibUVSourceIO final : public LibUVSource<EventSourceIO, uv_poll_t>,
115  public TrackableObject<LibUVSourceIO> {
116  LibUVSourceIO(IOCallback _callback, std::shared_ptr<UVLoop> loop, int fd,
117  IOEventFlags flags)
118  : LibUVSource(std::move(loop)), fd_(fd), flags_(flags),
119  callback_(std::make_shared<IOCallback>(std::move(_callback))) {
120  setEnabled(true);
121  }
122 
123  virtual int fd() const override { return fd_; }
124 
125  virtual void setFd(int fd) override {
126  if (fd_ != fd) {
127  fd_ = fd;
128  resetEvent();
129  }
130  }
131 
132  virtual IOEventFlags events() const override { return flags_; }
133 
134  void setEvents(IOEventFlags flags) override {
135  if (flags_ != flags) {
136  flags_ = flags;
137  resetEvent();
138  }
139  }
140 
141  IOEventFlags revents() const override { return revents_; }
142 
143  bool setup(uv_loop_t *loop, uv_poll_t *poll) override;
144 
145  int fd_;
146  IOEventFlags flags_;
147  IOEventFlags revents_;
148  std::shared_ptr<IOCallback> callback_;
149 };
150 
151 struct LibUVSourceTime final : public LibUVSource<EventSourceTime, uv_timer_t>,
152  public TrackableObject<LibUVSourceTime> {
153  LibUVSourceTime(TimeCallback _callback, std::shared_ptr<UVLoop> loop,
154  uint64_t time, clockid_t clockid, uint64_t accuracy)
155  : LibUVSource(std::move(loop)), time_(time), clock_(clockid),
156  accuracy_(accuracy),
157  callback_(std::make_shared<TimeCallback>(std::move(_callback))) {
158  setOneShot();
159  }
160 
161  uint64_t time() const override { return time_; }
162 
163  void setTime(uint64_t time) override {
164  time_ = time;
165  resetEvent();
166  }
167 
168  uint64_t accuracy() const override { return accuracy_; }
169 
170  void setAccuracy(uint64_t time) override { accuracy_ = time; }
171 
172  void setClock(clockid_t clockid) {
173  clock_ = clockid;
174  resetEvent();
175  }
176 
177  clockid_t clock() const override { return clock_; }
178 
179  bool setup(uv_loop_t *loop, uv_timer_t *timer) override;
180 
181  uint64_t time_;
182  clockid_t clock_;
183  uint64_t accuracy_;
184  std::shared_ptr<TimeCallback> callback_;
185 };
186 
187 struct LibUVSourcePost final : public LibUVSource<EventSource, uv_prepare_t>,
188  public TrackableObject<LibUVSourcePost> {
189  LibUVSourcePost(EventCallback callback, std::shared_ptr<UVLoop> loop)
190  : LibUVSource(std::move(loop)),
191  callback_(std::make_shared<EventCallback>(std::move(callback))) {
192  setEnabled(true);
193  }
194 
195  bool setup(uv_loop_t *loop, uv_prepare_t *prepare) override;
196 
197  std::shared_ptr<EventCallback> callback_;
198 };
199 
200 struct LibUVSourceExit final : public EventSource,
201  public TrackableObject<LibUVSourceExit> {
202  LibUVSourceExit(EventCallback _callback)
203  : callback_(std::move(_callback)) {}
204 
205  bool isOneShot() const override {
206  return state_ == LibUVSourceEnableState::Oneshot;
207  }
208  bool isEnabled() const override {
209  return state_ != LibUVSourceEnableState::Disabled;
210  }
211  void setEnabled(bool enabled) override {
212  state_ = enabled ? LibUVSourceEnableState::Enabled
213  : LibUVSourceEnableState::Disabled;
214  }
215 
216  void setOneShot() override { state_ = LibUVSourceEnableState::Oneshot; }
217 
218  LibUVSourceEnableState state_ = LibUVSourceEnableState::Oneshot;
219  EventCallback callback_;
220 };
221 
222 struct LibUVSourceAsync final
223  : public LibUVSource<EventSourceAsync, uv_async_t>,
224  public TrackableObject<LibUVSourceAsync> {
225  LibUVSourceAsync(EventCallback callback, std::shared_ptr<UVLoop> loop)
226  : LibUVSource(std::move(loop)),
227  callback_(std::make_shared<EventCallback>(std::move(callback))) {
228  setEnabled(true);
229  }
230 
231  bool setup(uv_loop_t *loop, uv_async_t *async) override;
232 
233  void send() override;
234 
235  std::shared_ptr<EventCallback> callback_;
236 };
237 
239 public:
240  EventLoopLibUV();
241  bool exec() override;
242  void exit() override;
243  const char *implementation() const override;
244  void *nativeHandle() override;
245 
246  FCITX_NODISCARD std::unique_ptr<EventSourceIO>
247  addIOEvent(int fd, IOEventFlags flags, IOCallback callback) override;
248  FCITX_NODISCARD std::unique_ptr<EventSourceTime>
249  addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy,
250  TimeCallback callback) override;
251  FCITX_NODISCARD std::unique_ptr<EventSource>
252  addExitEvent(EventCallback callback) override;
253  FCITX_NODISCARD std::unique_ptr<EventSource>
254  addDeferEvent(EventCallback callback) override;
255  FCITX_NODISCARD std::unique_ptr<EventSource>
256  addPostEvent(EventCallback callback) override;
257  FCITX_NODISCARD std::unique_ptr<EventSourceAsync>
258  addAsyncEvent(EventCallback callback) override;
259 
260 private:
261  std::shared_ptr<UVLoop> loop_;
262  std::vector<TrackableObjectReference<LibUVSourceExit>> exitEvents_;
263 };
264 
265 } // namespace fcitx
266 
267 #endif // _FCITX_UTILS_EVENT_LIBUV_H_
Utitliy classes for statically tracking the life of a object.
Definition: action.cpp:17
Helper class to be used with TrackableObjectReference.
Log utilities.