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