From 0c415a160384546976fb7595b107bb794e86d9ee Mon Sep 17 00:00:00 2001 From: Weng Xuetian Date: Tue, 12 Nov 2024 07:38:55 -0800 Subject: [PATCH] Refactor EventLoop class and introduce a new virtual-base class EventLoopInterface (#1175) --- src/lib/fcitx-utils/CMakeLists.txt | 3 +- src/lib/fcitx-utils/event.cpp | 86 +++++ src/lib/fcitx-utils/event.h | 63 +--- src/lib/fcitx-utils/event_libuv.cpp | 345 ++++-------------- src/lib/fcitx-utils/event_libuv.h | 249 +++++++++++++ src/lib/fcitx-utils/event_p.h | 21 ++ src/lib/fcitx-utils/event_sdevent.cpp | 115 +++--- ...vent_common.cpp => eventloopinterface.cpp} | 12 +- src/lib/fcitx-utils/eventloopinterface.h | 136 +++++++ 9 files changed, 645 insertions(+), 385 deletions(-) create mode 100644 src/lib/fcitx-utils/event.cpp create mode 100644 src/lib/fcitx-utils/event_libuv.h create mode 100644 src/lib/fcitx-utils/event_p.h rename src/lib/fcitx-utils/{event_common.cpp => eventloopinterface.cpp} (84%) create mode 100644 src/lib/fcitx-utils/eventloopinterface.h diff --git a/src/lib/fcitx-utils/CMakeLists.txt b/src/lib/fcitx-utils/CMakeLists.txt index dd67e07db..5276f5357 100644 --- a/src/lib/fcitx-utils/CMakeLists.txt +++ b/src/lib/fcitx-utils/CMakeLists.txt @@ -45,7 +45,6 @@ set(FCITX_UTILS_SOURCES cutf8.cpp color.cpp i18nstring.cpp - event_common.cpp eventdispatcher.cpp library.cpp fs.cpp @@ -60,6 +59,8 @@ set(FCITX_UTILS_SOURCES misc.cpp semver.cpp keydata.cpp + event.cpp + eventloopinterface.cpp ) set(FCITX_UTILS_HEADERS diff --git a/src/lib/fcitx-utils/event.cpp b/src/lib/fcitx-utils/event.cpp new file mode 100644 index 000000000..ce11aebf5 --- /dev/null +++ b/src/lib/fcitx-utils/event.cpp @@ -0,0 +1,86 @@ + +/* + * SPDX-FileCopyrightText: 2015-2015 CSSlayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + */ + +#include "event.h" +#include +#include +#include +#include +#include +#include "event_p.h" +#include "eventloopinterface.h" +#include "macros.h" + +namespace fcitx { + +class EventLoopPrivate { +public: + EventLoopPrivate(std::unique_ptr impl) + : impl_(std::move(impl)) {} + + std::unique_ptr impl_; +}; + +EventLoop::EventLoop() : EventLoop(createDefaultEventLoop()) {} + +EventLoop::EventLoop(std::unique_ptr impl) + : d_ptr(std::make_unique(std::move(impl))) {} + +EventLoop::~EventLoop() = default; + +const char *EventLoop::impl() { return defaultEventLoopImplementation(); } + +const char *EventLoop::implementation() const { + FCITX_D(); + return d->impl_->implementation(); +} + +void *EventLoop::nativeHandle() { + FCITX_D(); + return d->impl_->nativeHandle(); +} + +bool EventLoop::exec() { + FCITX_D(); + return d->impl_->exec(); +} + +void EventLoop::exit() { + FCITX_D(); + return d->impl_->exit(); +} + +std::unique_ptr EventLoop::addIOEvent(int fd, IOEventFlags flags, + IOCallback callback) { + FCITX_D(); + return d->impl_->addIOEvent(fd, flags, std::move(callback)); +} + +std::unique_ptr +EventLoop::addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy, + TimeCallback callback) { + FCITX_D(); + return d->impl_->addTimeEvent(clock, usec, accuracy, std::move(callback)); +} + +std::unique_ptr EventLoop::addExitEvent(EventCallback callback) { + FCITX_D(); + return d->impl_->addExitEvent(std::move(callback)); +} + +std::unique_ptr EventLoop::addDeferEvent(EventCallback callback) { + FCITX_D(); + return d->impl_->addDeferEvent(std::move(callback)); +} + +std::unique_ptr EventLoop::addPostEvent(EventCallback callback) { + FCITX_D(); + return d->impl_->addPostEvent(std::move(callback)); +} + +} // namespace fcitx diff --git a/src/lib/fcitx-utils/event.h b/src/lib/fcitx-utils/event.h index 066df708b..11b4e8ac6 100644 --- a/src/lib/fcitx-utils/event.h +++ b/src/lib/fcitx-utils/event.h @@ -8,76 +8,29 @@ #define _FCITX_UTILS_EVENT_H_ #include -#include #include -#include +#include #include #include #include "fcitxutils_export.h" namespace fcitx { -enum class IOEventFlag { - In = (1 << 0), - Out = (1 << 1), - Err = (1 << 2), - Hup = (1 << 3), - EdgeTrigger = (1 << 4), -}; - -using IOEventFlags = Flags; - -class FCITXUTILS_EXPORT EventLoopException : public std::runtime_error { -public: - EventLoopException(int error); - - FCITX_NODISCARD int error() const { return errno_; } - -private: - int errno_; -}; - -struct FCITXUTILS_EXPORT EventSource { - virtual ~EventSource(); - FCITX_NODISCARD virtual bool isEnabled() const = 0; - virtual void setEnabled(bool enabled) = 0; - FCITX_NODISCARD virtual bool isOneShot() const = 0; - virtual void setOneShot() = 0; -}; - -struct FCITXUTILS_EXPORT EventSourceIO : public EventSource { - FCITX_NODISCARD virtual int fd() const = 0; - virtual void setFd(int fd) = 0; - FCITX_NODISCARD virtual IOEventFlags events() const = 0; - virtual void setEvents(IOEventFlags flags) = 0; - FCITX_NODISCARD virtual IOEventFlags revents() const = 0; -}; - -struct FCITXUTILS_EXPORT EventSourceTime : public EventSource { - virtual void setNextInterval(uint64_t time); - FCITX_NODISCARD virtual uint64_t time() const = 0; - virtual void setTime(uint64_t time) = 0; - FCITX_NODISCARD virtual uint64_t accuracy() const = 0; - virtual void setAccuracy(uint64_t accuracy) = 0; - FCITX_NODISCARD virtual clockid_t clock() const = 0; -}; - -using IOCallback = - std::function; -using TimeCallback = std::function; -using EventCallback = std::function; - -FCITXUTILS_EXPORT uint64_t now(clockid_t clock); - class EventLoopPrivate; class FCITXUTILS_EXPORT EventLoop { public: EventLoop(); + EventLoop(std::unique_ptr impl); virtual ~EventLoop(); bool exec(); void exit(); - static const char *impl(); + /** + * Return the default implementation name. + */ + FCITXUTILS_DEPRECATED static const char *impl(); + + const char *implementation() const; void *nativeHandle(); FCITX_NODISCARD std::unique_ptr diff --git a/src/lib/fcitx-utils/event_libuv.cpp b/src/lib/fcitx-utils/event_libuv.cpp index f84c7e360..6e6580cbe 100644 --- a/src/lib/fcitx-utils/event_libuv.cpp +++ b/src/lib/fcitx-utils/event_libuv.cpp @@ -6,13 +6,18 @@ * */ +#include "event_libuv.h" +#include +#include #include #include #include #include +#include #include #include -#include "event.h" +#include "event_p.h" +#include "eventloopinterface.h" #include "log.h" #include "trackableobject.h" @@ -20,6 +25,12 @@ namespace fcitx { +std::unique_ptr createDefaultEventLoop() { + return std::make_unique(); +} + +const char *defaultEventLoopImplementation() { return "libuv"; } + FCITX_DEFINE_LOG_CATEGORY(libuv_logcategory, "libuv"); static int IOEventFlagsToLibUVFlags(IOEventFlags flags) { @@ -46,60 +57,6 @@ void IOEventCallback(uv_poll_t *handle, int status, int events); void TimeEventCallback(uv_timer_t *handle); void PostEventCallback(uv_prepare_t *handle); -enum class LibUVSourceEnableState { Disabled = 0, Oneshot = 1, Enabled = 2 }; - -struct UVLoop { - UVLoop() { uv_loop_init(&loop_); } - - ~UVLoop(); - - operator uv_loop_t *() { return &loop_; } - - uv_loop_t loop_; -}; - -struct LibUVSourceBase { -public: - LibUVSourceBase(std::shared_ptr loop) : loop_(loop) {} - - virtual ~LibUVSourceBase() { cleanup(); }; - void cleanup() { - if (!handle_) { - return; - } - auto *handle = handle_; - handle_->data = nullptr; - handle_ = nullptr; - uv_close(handle, [](uv_handle_t *handle) { free(handle); }); - } - - virtual void init(uv_loop_t *loop) = 0; - - void resetEvent() { - cleanup(); - if (state_ == LibUVSourceEnableState::Disabled) { - return; - } - auto loop = loop_.lock(); - if (!loop) { - return; - } - init(*loop); - } - -protected: - void setState(LibUVSourceEnableState state) { - if (state_ != state) { - state_ = state; - resetEvent(); - } - } - - std::weak_ptr loop_; - uv_handle_t *handle_ = nullptr; - LibUVSourceEnableState state_ = LibUVSourceEnableState::Disabled; -}; - UVLoop::~UVLoop() { // Close and detach all handle. uv_walk( @@ -125,212 +82,58 @@ UVLoop::~UVLoop() { FCITX_DEBUG() << "UVLoop close r2: " << r; } -template -struct LibUVSource : public Interface, public LibUVSourceBase { -public: - LibUVSource(std::shared_ptr loop) - : LibUVSourceBase(std::move(loop)) {} - - bool isEnabled() const override { - return state_ != LibUVSourceEnableState::Disabled; - } - void setEnabled(bool enabled) override { - auto newState = enabled ? LibUVSourceEnableState::Enabled - : LibUVSourceEnableState::Disabled; - setState(newState); - } - - void setOneShot() override { setState(LibUVSourceEnableState::Oneshot); } - - bool isOneShot() const override { - return state_ == LibUVSourceEnableState::Oneshot; - } - - inline HandleType *handle() { - return reinterpret_cast(handle_); - } - - void init(uv_loop_t *loop) override { - handle_ = static_cast(calloc(1, sizeof(HandleType))); - handle_->data = static_cast(this); - if (!setup(loop, handle())) { - free(handle_); - handle_ = nullptr; - } - } - - virtual bool setup(uv_loop_t *loop, HandleType *handle) = 0; -}; - -struct LibUVSourceIO final : public LibUVSource, - public TrackableObject { - LibUVSourceIO(IOCallback _callback, std::shared_ptr loop, int fd, - IOEventFlags flags) - : LibUVSource(loop), fd_(fd), flags_(flags), - callback_(std::make_shared(std::move(_callback))) { - setEnabled(true); - } - - virtual int fd() const override { return fd_; } - - virtual void setFd(int fd) override { - if (fd_ != fd) { - fd_ = fd; - resetEvent(); - } - } - - virtual IOEventFlags events() const override { return flags_; } - - void setEvents(IOEventFlags flags) override { - if (flags_ != flags) { - flags_ = flags; - resetEvent(); - } - } - - IOEventFlags revents() const override { return revents_; } - - bool setup(uv_loop_t *loop, uv_poll_t *poll) override { - if (int err = uv_poll_init(loop, poll, fd_); err < 0) { - FCITX_LIBUV_DEBUG() << "Failed to init poll for fd: " << fd_ - << " with error: " << err; - return false; - } - const auto flags = IOEventFlagsToLibUVFlags(flags_); - if (int err = uv_poll_start(poll, flags, &IOEventCallback); err < 0) { - FCITX_LIBUV_DEBUG() << "Failed to start poll with error: " << err; - return false; - } - return true; +bool LibUVSourceTime::setup(uv_loop_t *loop, uv_timer_t *timer) { + if (int err = uv_timer_init(loop, timer); err < 0) { + FCITX_LIBUV_DEBUG() << "Failed to init timer with error: " << err; + return false; } - - int fd_; - IOEventFlags flags_; - IOEventFlags revents_; - std::shared_ptr callback_; -}; - -struct LibUVSourceTime final : public LibUVSource, - public TrackableObject { - LibUVSourceTime(TimeCallback _callback, std::shared_ptr loop, - uint64_t time, clockid_t clockid, uint64_t accuracy) - : LibUVSource(std::move(loop)), time_(time), clock_(clockid), - accuracy_(accuracy), - callback_(std::make_shared(std::move(_callback))) { - setOneShot(); - } - - virtual uint64_t time() const override { return time_; } - - virtual void setTime(uint64_t time) override { - time_ = time; - resetEvent(); + auto curr = now(clock_); + uint64_t timeout = time_ > curr ? (time_ - curr) : 0; + // libuv is milliseconds + timeout /= 1000; + if (int err = uv_timer_start(timer, &TimeEventCallback, timeout, 0); + err < 0) { + FCITX_LIBUV_DEBUG() << "Failed to start timer with error: " << err; + return false; } - - virtual uint64_t accuracy() const override { return accuracy_; } - - virtual void setAccuracy(uint64_t time) override { accuracy_ = time; } - - void setClock(clockid_t clockid) { - clock_ = clockid; - resetEvent(); - } - - virtual clockid_t clock() const override { return clock_; } - - bool setup(uv_loop_t *loop, uv_timer_t *timer) override { - if (int err = uv_timer_init(loop, timer); err < 0) { - FCITX_LIBUV_DEBUG() << "Failed to init timer with error: " << err; - return false; - } - auto curr = now(clock_); - uint64_t timeout = time_ > curr ? (time_ - curr) : 0; - // libuv is milliseconds - timeout /= 1000; - if (int err = uv_timer_start(timer, &TimeEventCallback, timeout, 0); - err < 0) { - FCITX_LIBUV_DEBUG() << "Failed to start timer with error: " << err; - return false; - } - return true; - } - - uint64_t time_; - clockid_t clock_; - uint64_t accuracy_; - std::shared_ptr callback_; -}; - -struct LibUVSourcePost final : public LibUVSource, - public TrackableObject { - LibUVSourcePost(EventCallback callback, std::shared_ptr loop) - : LibUVSource(std::move(loop)), - callback_(std::make_shared(std::move(callback))) { - setEnabled(true); - } - - bool setup(uv_loop_t *loop, uv_prepare_t *prepare) override { - if (int err = uv_prepare_init(loop, prepare); err < 0) { - FCITX_LIBUV_DEBUG() << "Failed to init prepare with error: " << err; - return false; - } - if (int err = uv_prepare_start(prepare, &PostEventCallback); err < 0) { - FCITX_LIBUV_DEBUG() - << "Failed to start prepare with error: " << err; - return false; - } - return true; + return true; +} +bool LibUVSourcePost::setup(uv_loop_t *loop, uv_prepare_t *prepare) { + if (int err = uv_prepare_init(loop, prepare); err < 0) { + FCITX_LIBUV_DEBUG() << "Failed to init prepare with error: " << err; + return false; } - - std::shared_ptr callback_; -}; - -struct LibUVSourceExit final : public EventSource, - public TrackableObject { - LibUVSourceExit(EventCallback _callback) - : callback_(std::move(_callback)) {} - - bool isOneShot() const override { - return state_ == LibUVSourceEnableState::Oneshot; + if (int err = uv_prepare_start(prepare, &PostEventCallback); err < 0) { + FCITX_LIBUV_DEBUG() << "Failed to start prepare with error: " << err; + return false; } - bool isEnabled() const override { - return state_ != LibUVSourceEnableState::Disabled; + return true; +} +bool LibUVSourceIO::setup(uv_loop_t *loop, uv_poll_t *poll) { + if (int err = uv_poll_init(loop, poll, fd_); err < 0) { + FCITX_LIBUV_DEBUG() + << "Failed to init poll for fd: " << fd_ << " with error: " << err; + return false; } - void setEnabled(bool enabled) override { - state_ = enabled ? LibUVSourceEnableState::Enabled - : LibUVSourceEnableState::Disabled; + const auto flags = IOEventFlagsToLibUVFlags(flags_); + if (int err = uv_poll_start(poll, flags, &IOEventCallback); err < 0) { + FCITX_LIBUV_DEBUG() << "Failed to start poll with error: " << err; + return false; } + return true; +} - void setOneShot() override { state_ = LibUVSourceEnableState::Oneshot; } - - LibUVSourceEnableState state_ = LibUVSourceEnableState::Oneshot; - EventCallback callback_; -}; - -class EventLoopPrivate { -public: - EventLoopPrivate() : loop_(std::make_shared()) {} - - std::shared_ptr loop_; - std::vector> exitEvents_; -}; - -EventLoop::EventLoop() : d_ptr(std::make_unique()) {} - -EventLoop::~EventLoop() {} +EventLoopLibUV::EventLoopLibUV() : loop_(std::make_shared()) {} -const char *EventLoop::impl() { return "libuv"; } +const char *EventLoopLibUV::implementation() const { return "libuv"; } -void *EventLoop::nativeHandle() { - FCITX_D(); - return static_cast(*d->loop_); +void *EventLoopLibUV::nativeHandle() { + return static_cast(*loop_); } -bool EventLoop::exec() { - FCITX_D(); - int r = uv_run(*d->loop_, UV_RUN_DEFAULT); - for (auto iter = d->exitEvents_.begin(); iter != d->exitEvents_.end();) { +bool EventLoopLibUV::exec() { + int r = uv_run(*loop_, UV_RUN_DEFAULT); + for (auto iter = exitEvents_.begin(); iter != exitEvents_.end();) { if (auto *event = iter->get()) { if (event->isEnabled()) { try { @@ -345,7 +148,7 @@ bool EventLoop::exec() { } } if (!iter->isValid()) { - iter = d->exitEvents_.erase(iter); + iter = exitEvents_.erase(iter); } else { ++iter; } @@ -353,10 +156,7 @@ bool EventLoop::exec() { return r >= 0; } -void EventLoop::exit() { - FCITX_D(); - uv_stop(*d->loop_); -} +void EventLoopLibUV::exit() { uv_stop(*loop_); } void IOEventCallback(uv_poll_t *handle, int status, int events) { auto *source = static_cast( @@ -383,11 +183,10 @@ void IOEventCallback(uv_poll_t *handle, int status, int events) { } } -std::unique_ptr EventLoop::addIOEvent(int fd, IOEventFlags flags, - IOCallback callback) { - FCITX_D(); - auto source = std::make_unique(std::move(callback), d->loop_, - fd, flags); +std::unique_ptr +EventLoopLibUV::addIOEvent(int fd, IOEventFlags flags, IOCallback callback) { + auto source = + std::make_unique(std::move(callback), loop_, fd, flags); return source; } @@ -417,22 +216,22 @@ void TimeEventCallback(uv_timer_t *handle) { } std::unique_ptr -EventLoop::addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy, - TimeCallback callback) { - FCITX_D(); - auto source = std::make_unique( - std::move(callback), d->loop_, usec, clock, accuracy); +EventLoopLibUV::addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy, + TimeCallback callback) { + auto source = std::make_unique(std::move(callback), loop_, + usec, clock, accuracy); return source; } -std::unique_ptr EventLoop::addExitEvent(EventCallback callback) { - FCITX_D(); +std::unique_ptr +EventLoopLibUV::addExitEvent(EventCallback callback) { auto source = std::make_unique(std::move(callback)); - d->exitEvents_.push_back(source->watch()); + exitEvents_.push_back(source->watch()); return source; } -std::unique_ptr EventLoop::addDeferEvent(EventCallback callback) { +std::unique_ptr +EventLoopLibUV::addDeferEvent(EventCallback callback) { return addTimeEvent( CLOCK_MONOTONIC, 0, 0, [callback = std::move(callback)](EventSourceTime *source, uint64_t) { @@ -457,11 +256,9 @@ void PostEventCallback(uv_prepare_t *handle) { } } -std::unique_ptr EventLoop::addPostEvent(EventCallback callback) { - FCITX_D(); - auto source = - std::make_unique(std::move(callback), d->loop_); +std::unique_ptr +EventLoopLibUV::addPostEvent(EventCallback callback) { + auto source = std::make_unique(std::move(callback), loop_); return source; } - } // namespace fcitx diff --git a/src/lib/fcitx-utils/event_libuv.h b/src/lib/fcitx-utils/event_libuv.h new file mode 100644 index 000000000..d379b75a9 --- /dev/null +++ b/src/lib/fcitx-utils/event_libuv.h @@ -0,0 +1,249 @@ +/* + * SPDX-FileCopyrightText: 2020~2020 CSSlayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + */ +#ifndef _FCITX_UTILS_EVENT_LIBUV_H_ +#define _FCITX_UTILS_EVENT_LIBUV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fcitx { + +struct UVLoop { + UVLoop() { uv_loop_init(&loop_); } + + ~UVLoop(); + + operator uv_loop_t *() { return &loop_; } + + uv_loop_t loop_; +}; + +enum class LibUVSourceEnableState { Disabled = 0, Oneshot = 1, Enabled = 2 }; + +struct LibUVSourceBase { +public: + LibUVSourceBase(const std::shared_ptr &loop) : loop_(loop) {} + + virtual ~LibUVSourceBase() { cleanup(); }; + void cleanup() { + if (!handle_) { + return; + } + auto *handle = handle_; + handle_->data = nullptr; + handle_ = nullptr; + uv_close(handle, [](uv_handle_t *handle) { free(handle); }); + } + + virtual void init(uv_loop_t *loop) = 0; + + void resetEvent() { + cleanup(); + if (state_ == LibUVSourceEnableState::Disabled) { + return; + } + auto loop = loop_.lock(); + if (!loop) { + return; + } + init(*loop); + } + +protected: + void setState(LibUVSourceEnableState state) { + if (state_ != state) { + state_ = state; + resetEvent(); + } + } + + std::weak_ptr loop_; + uv_handle_t *handle_ = nullptr; + LibUVSourceEnableState state_ = LibUVSourceEnableState::Disabled; +}; + +template +struct LibUVSource : public Interface, public LibUVSourceBase { +public: + LibUVSource(std::shared_ptr loop) + : LibUVSourceBase(std::move(loop)) {} + + bool isEnabled() const override { + return state_ != LibUVSourceEnableState::Disabled; + } + void setEnabled(bool enabled) override { + auto newState = enabled ? LibUVSourceEnableState::Enabled + : LibUVSourceEnableState::Disabled; + setState(newState); + } + + void setOneShot() override { setState(LibUVSourceEnableState::Oneshot); } + + bool isOneShot() const override { + return state_ == LibUVSourceEnableState::Oneshot; + } + + inline HandleType *handle() { + return reinterpret_cast(handle_); + } + + void init(uv_loop_t *loop) override { + handle_ = static_cast(calloc(1, sizeof(HandleType))); + handle_->data = static_cast(this); + if (!setup(loop, handle())) { + free(handle_); + handle_ = nullptr; + } + } + + virtual bool setup(uv_loop_t *loop, HandleType *handle) = 0; +}; + +struct LibUVSourceIO final : public LibUVSource, + public TrackableObject { + LibUVSourceIO(IOCallback _callback, std::shared_ptr loop, int fd, + IOEventFlags flags) + : LibUVSource(std::move(loop)), fd_(fd), flags_(flags), + callback_(std::make_shared(std::move(_callback))) { + setEnabled(true); + } + + virtual int fd() const override { return fd_; } + + virtual void setFd(int fd) override { + if (fd_ != fd) { + fd_ = fd; + resetEvent(); + } + } + + virtual IOEventFlags events() const override { return flags_; } + + void setEvents(IOEventFlags flags) override { + if (flags_ != flags) { + flags_ = flags; + resetEvent(); + } + } + + IOEventFlags revents() const override { return revents_; } + + bool setup(uv_loop_t *loop, uv_poll_t *poll) override; + + int fd_; + IOEventFlags flags_; + IOEventFlags revents_; + std::shared_ptr callback_; +}; + +struct LibUVSourceTime final : public LibUVSource, + public TrackableObject { + LibUVSourceTime(TimeCallback _callback, std::shared_ptr loop, + uint64_t time, clockid_t clockid, uint64_t accuracy) + : LibUVSource(std::move(loop)), time_(time), clock_(clockid), + accuracy_(accuracy), + callback_(std::make_shared(std::move(_callback))) { + setOneShot(); + } + + uint64_t time() const override { return time_; } + + void setTime(uint64_t time) override { + time_ = time; + resetEvent(); + } + + uint64_t accuracy() const override { return accuracy_; } + + void setAccuracy(uint64_t time) override { accuracy_ = time; } + + void setClock(clockid_t clockid) { + clock_ = clockid; + resetEvent(); + } + + clockid_t clock() const override { return clock_; } + + bool setup(uv_loop_t *loop, uv_timer_t *timer) override; + + uint64_t time_; + clockid_t clock_; + uint64_t accuracy_; + std::shared_ptr callback_; +}; + +struct LibUVSourcePost final : public LibUVSource, + public TrackableObject { + LibUVSourcePost(EventCallback callback, std::shared_ptr loop) + : LibUVSource(std::move(loop)), + callback_(std::make_shared(std::move(callback))) { + setEnabled(true); + } + + bool setup(uv_loop_t *loop, uv_prepare_t *prepare) override; + + std::shared_ptr callback_; +}; + +struct LibUVSourceExit final : public EventSource, + public TrackableObject { + LibUVSourceExit(EventCallback _callback) + : callback_(std::move(_callback)) {} + + bool isOneShot() const override { + return state_ == LibUVSourceEnableState::Oneshot; + } + bool isEnabled() const override { + return state_ != LibUVSourceEnableState::Disabled; + } + void setEnabled(bool enabled) override { + state_ = enabled ? LibUVSourceEnableState::Enabled + : LibUVSourceEnableState::Disabled; + } + + void setOneShot() override { state_ = LibUVSourceEnableState::Oneshot; } + + LibUVSourceEnableState state_ = LibUVSourceEnableState::Oneshot; + EventCallback callback_; +}; + +class EventLoopLibUV : public EventLoopInterface { +public: + EventLoopLibUV(); + bool exec() override; + void exit() override; + const char *implementation() const override; + void *nativeHandle() override; + + FCITX_NODISCARD std::unique_ptr + addIOEvent(int fd, IOEventFlags flags, IOCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy, + TimeCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addExitEvent(EventCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addDeferEvent(EventCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addPostEvent(EventCallback callback) override; + +private: + std::shared_ptr loop_; + std::vector> exitEvents_; +}; + +} // namespace fcitx + +#endif // _FCITX_UTILS_EVENT_LIBUV_H_ diff --git a/src/lib/fcitx-utils/event_p.h b/src/lib/fcitx-utils/event_p.h new file mode 100644 index 000000000..836a8a087 --- /dev/null +++ b/src/lib/fcitx-utils/event_p.h @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2015-2015 CSSlayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + */ +#ifndef _FCITX_UTILS_EVENT_P_H_ +#define _FCITX_UTILS_EVENT_P_H_ + +#include +#include + +namespace fcitx { + +std::unique_ptr createDefaultEventLoop(); + +const char *defaultEventLoopImplementation(); + +} // namespace fcitx + +#endif // _FCITX_UTILS_EVENT_P_H_ diff --git a/src/lib/fcitx-utils/event_sdevent.cpp b/src/lib/fcitx-utils/event_sdevent.cpp index 0994f5e64..77ba903d9 100644 --- a/src/lib/fcitx-utils/event_sdevent.cpp +++ b/src/lib/fcitx-utils/event_sdevent.cpp @@ -14,15 +14,15 @@ #include #include #include +#include "fcitx-utils/macros.h" +#include "eventloopinterface.h" +#include "log.h" +#include "stringutils.h" #if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) #define __INCLUDE_LEVEL__ 2 #endif #include -#include "event.h" -#include "log.h" -#include "macros.h" -#include "stringutils.h" namespace fcitx { @@ -57,6 +57,38 @@ IOEventFlags EpollFlagsToIOEventFlags(uint32_t flags) { } // namespace +class EventLoopSDEvent : public EventLoopInterface { +public: + EventLoopSDEvent(); + ~EventLoopSDEvent(); + bool exec() override; + void exit() override; + const char *implementation() const override; + void *nativeHandle() override; + + FCITX_NODISCARD std::unique_ptr + addIOEvent(int fd, IOEventFlags flags, IOCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy, + TimeCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addExitEvent(EventCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addDeferEvent(EventCallback callback) override; + FCITX_NODISCARD std::unique_ptr + addPostEvent(EventCallback callback) override; + +private: + std::mutex mutex_; + sd_event *event_ = nullptr; +}; + +std::unique_ptr createDefaultEventLoop() { + return std::make_unique(); +} + +const char *defaultEventLoopImplementation() { return "sd-event"; } + template struct SDEventSourceBase : public Interface { public: @@ -204,42 +236,25 @@ struct SDEventSourceTime : public SDEventSourceBase { std::shared_ptr callback_; }; -class EventLoopPrivate { -public: - EventLoopPrivate() { - if (int rc = sd_event_new(&event_); rc < 0) { - throw std::runtime_error(stringutils::concat( - "Create sd_event failed. error code: ", rc)); - } +EventLoopSDEvent::EventLoopSDEvent() { + if (int rc = sd_event_new(&event_); rc < 0) { + throw std::runtime_error( + stringutils::concat("Create sd_event failed. error code: ", rc)); } +} - ~EventLoopPrivate() { sd_event_unref(event_); } - - std::mutex mutex_; - sd_event *event_ = nullptr; -}; - -EventLoop::EventLoop() : d_ptr(std::make_unique()) {} +EventLoopSDEvent::~EventLoopSDEvent() { sd_event_unref(event_); }; -EventLoop::~EventLoop() = default; +const char *EventLoopSDEvent::implementation() const { return "sd-event"; } -const char *EventLoop::impl() { return "sd-event"; } +void *EventLoopSDEvent::nativeHandle() { return event_; } -void *EventLoop::nativeHandle() { - FCITX_D(); - return d->event_; -} - -bool EventLoop::exec() { - FCITX_D(); - int r = sd_event_loop(d->event_); +bool EventLoopSDEvent::exec() { + int r = sd_event_loop(event_); return r >= 0; } -void EventLoop::exit() { - FCITX_D(); - sd_event_exit(d->event_, 0); -} +void EventLoopSDEvent::exit() { sd_event_exit(event_, 0); } int IOEventCallback(sd_event_source * /*unused*/, int fd, uint32_t revents, void *userdata) { @@ -258,12 +273,11 @@ int IOEventCallback(sd_event_source * /*unused*/, int fd, uint32_t revents, return -1; } -std::unique_ptr EventLoop::addIOEvent(int fd, IOEventFlags flags, - IOCallback callback) { - FCITX_D(); +std::unique_ptr +EventLoopSDEvent::addIOEvent(int fd, IOEventFlags flags, IOCallback callback) { auto source = std::make_unique(std::move(callback)); sd_event_source *sdEventSource; - if (int err = sd_event_add_io(d->event_, &sdEventSource, fd, + if (int err = sd_event_add_io(event_, &sdEventSource, fd, IOEventFlagsToEpollFlags(flags), IOEventCallback, source.get()); err < 0) { @@ -292,12 +306,11 @@ int TimeEventCallback(sd_event_source * /*unused*/, uint64_t usec, } std::unique_ptr -EventLoop::addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy, - TimeCallback callback) { - FCITX_D(); +EventLoopSDEvent::addTimeEvent(clockid_t clock, uint64_t usec, + uint64_t accuracy, TimeCallback callback) { auto source = std::make_unique(std::move(callback)); sd_event_source *sdEventSource; - if (int err = sd_event_add_time(d->event_, &sdEventSource, clock, usec, + if (int err = sd_event_add_time(event_, &sdEventSource, clock, usec, accuracy, TimeEventCallback, source.get()); err < 0) { throw EventLoopException(err); @@ -323,12 +336,12 @@ int StaticEventCallback(sd_event_source * /*unused*/, void *userdata) { return -1; } -std::unique_ptr EventLoop::addExitEvent(EventCallback callback) { - FCITX_D(); +std::unique_ptr +EventLoopSDEvent::addExitEvent(EventCallback callback) { auto source = std::make_unique(std::move(callback)); sd_event_source *sdEventSource; - if (int err = sd_event_add_exit(d->event_, &sdEventSource, - StaticEventCallback, source.get()); + if (int err = sd_event_add_exit(event_, &sdEventSource, StaticEventCallback, + source.get()); err < 0) { throw EventLoopException(err); } @@ -336,11 +349,11 @@ std::unique_ptr EventLoop::addExitEvent(EventCallback callback) { return source; } -std::unique_ptr EventLoop::addDeferEvent(EventCallback callback) { - FCITX_D(); +std::unique_ptr +EventLoopSDEvent::addDeferEvent(EventCallback callback) { auto source = std::make_unique(std::move(callback)); sd_event_source *sdEventSource; - if (int err = sd_event_add_defer(d->event_, &sdEventSource, + if (int err = sd_event_add_defer(event_, &sdEventSource, StaticEventCallback, source.get()); err < 0) { throw EventLoopException(err); @@ -349,12 +362,12 @@ std::unique_ptr EventLoop::addDeferEvent(EventCallback callback) { return source; } -std::unique_ptr EventLoop::addPostEvent(EventCallback callback) { - FCITX_D(); +std::unique_ptr +EventLoopSDEvent::addPostEvent(EventCallback callback) { auto source = std::make_unique(std::move(callback)); sd_event_source *sdEventSource; - if (int err = sd_event_add_post(d->event_, &sdEventSource, - StaticEventCallback, source.get()); + if (int err = sd_event_add_post(event_, &sdEventSource, StaticEventCallback, + source.get()); err < 0) { throw EventLoopException(err); } diff --git a/src/lib/fcitx-utils/event_common.cpp b/src/lib/fcitx-utils/eventloopinterface.cpp similarity index 84% rename from src/lib/fcitx-utils/event_common.cpp rename to src/lib/fcitx-utils/eventloopinterface.cpp index ee5d72056..02f367b35 100644 --- a/src/lib/fcitx-utils/event_common.cpp +++ b/src/lib/fcitx-utils/eventloopinterface.cpp @@ -1,13 +1,14 @@ - /* - * SPDX-FileCopyrightText: 2015-2015 CSSlayer + * SPDX-FileCopyrightText: 2015-2024 CSSlayer * * SPDX-License-Identifier: LGPL-2.1-or-later * */ - +#include "eventloopinterface.h" +#include #include -#include "event.h" +#include +#include namespace fcitx { @@ -49,4 +50,7 @@ void EventSourceTime::setNextInterval(uint64_t time) { } EventSource::~EventSource() = default; + +EventLoopInterface::~EventLoopInterface() = default; + } // namespace fcitx diff --git a/src/lib/fcitx-utils/eventloopinterface.h b/src/lib/fcitx-utils/eventloopinterface.h new file mode 100644 index 000000000..963f96ce6 --- /dev/null +++ b/src/lib/fcitx-utils/eventloopinterface.h @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2024-2024 CSSlayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + */ +#ifndef _FCITX_UTILS_EVENTLOOPINTERFACE_H_ +#define _FCITX_UTILS_EVENTLOOPINTERFACE_H_ + +#include +#include +#include +#include +#include +#include +#include "fcitxutils_export.h" + +namespace fcitx { + +enum class IOEventFlag { + In = (1 << 0), + Out = (1 << 1), + Err = (1 << 2), + Hup = (1 << 3), + EdgeTrigger = (1 << 4), +}; + +using IOEventFlags = Flags; + +class FCITXUTILS_EXPORT EventLoopException : public std::runtime_error { +public: + EventLoopException(int error); + + FCITX_NODISCARD int error() const { return errno_; } + +private: + int errno_; +}; + +struct FCITXUTILS_EXPORT EventSource { + virtual ~EventSource(); + FCITX_NODISCARD virtual bool isEnabled() const = 0; + virtual void setEnabled(bool enabled) = 0; + FCITX_NODISCARD virtual bool isOneShot() const = 0; + virtual void setOneShot() = 0; +}; + +struct FCITXUTILS_EXPORT EventSourceIO : public EventSource { + FCITX_NODISCARD virtual int fd() const = 0; + virtual void setFd(int fd) = 0; + FCITX_NODISCARD virtual IOEventFlags events() const = 0; + virtual void setEvents(IOEventFlags flags) = 0; + FCITX_NODISCARD virtual IOEventFlags revents() const = 0; +}; + +struct FCITXUTILS_EXPORT EventSourceTime : public EventSource { + virtual void setNextInterval(uint64_t time); + FCITX_NODISCARD virtual uint64_t time() const = 0; + virtual void setTime(uint64_t time) = 0; + FCITX_NODISCARD virtual uint64_t accuracy() const = 0; + virtual void setAccuracy(uint64_t accuracy) = 0; + FCITX_NODISCARD virtual clockid_t clock() const = 0; +}; + +using IOCallback = + std::function; +using TimeCallback = std::function; +using EventCallback = std::function; + +FCITXUTILS_EXPORT uint64_t now(clockid_t clock); + +/** + * @brief Abstract Event Loop + * + * @since 5.1.12 + */ +class FCITXUTILS_EXPORT EventLoopInterface { +public: + virtual ~EventLoopInterface(); + + /** + * @brief Execute event loop + * + * @return true if event loop is exited successfully. + */ + virtual bool exec() = 0; + + /** + * @brief Quit event loop + * + * Request event loop to quit, pending event may still be executed before + * quit. Also execute exit event right before exiting. + * + * @see EventLoopInterface::addExitEvent + */ + virtual void exit() = 0; + + /** + * @brief Return a static implementation name of event loop + * + * Fcitx right now supports sd-event and libuv as implementation. + * The library being used is decided at build time. + * + * @return Name of event loop implementation + */ + virtual const char *implementation() const = 0; + + /** + * @brief Return the internal native handle to the event loop. + * + * This can be useful if you want to use the underlying API against + * event loop. + * + * For libuv, it will be uv_loop_t*. + * For sd-event, it will be sd_event*. + * + * @return internal implementation + * @see implementation + */ + virtual void *nativeHandle() = 0; + + FCITX_NODISCARD std::unique_ptr virtual addIOEvent( + int fd, IOEventFlags flags, IOCallback callback) = 0; + FCITX_NODISCARD std::unique_ptr virtual addTimeEvent( + clockid_t clock, uint64_t usec, uint64_t accuracy, + TimeCallback callback) = 0; + FCITX_NODISCARD virtual std::unique_ptr + addExitEvent(EventCallback callback) = 0; + FCITX_NODISCARD virtual std::unique_ptr + addDeferEvent(EventCallback callback) = 0; + FCITX_NODISCARD virtual std::unique_ptr + addPostEvent(EventCallback callback) = 0; +}; +} // namespace fcitx + +#endif // _FCITX_UTILS_EVENTLOOPINTERFACE_H_