From 46bab7e4b921b79924643bacd08dcd3d1404ceb6 Mon Sep 17 00:00:00 2001 From: Denis Krjuchkov Date: Wed, 27 Nov 2013 17:04:38 +0600 Subject: [PATCH] Add infrastructure for using multiple event loops This change adds two configuration options: --with-eventloop=[glib|internal|auto] --with-pollmethod=[epoll|auto] First allows switching between GLib event loop and internal one. Second chooses backend to use for internal event loop. Conditional compilation symbols are changed accordingly. Additional helper macro MPD_OPTIONAL_FUNC_NODEF is added as well. --- configure.ac | 68 +++++++++++++++++++++++++++++++- m4/mpd_func.m4 | 13 ++++++ src/event/Call.cxx | 15 ++++--- src/event/DeferredMonitor.cxx | 16 +++++--- src/event/DeferredMonitor.hxx | 39 +++++++++++------- src/event/IdleMonitor.cxx | 17 ++++---- src/event/IdleMonitor.hxx | 24 ++++++----- src/event/Loop.cxx | 23 ++++++++--- src/event/Loop.hxx | 33 +++++++++++----- src/event/MultiSocketMonitor.cxx | 6 ++- src/event/MultiSocketMonitor.hxx | 48 ++++++++++++++-------- src/event/SocketMonitor.cxx | 20 ++++++---- src/event/SocketMonitor.hxx | 41 +++++++++++++------ src/event/TimeoutMonitor.cxx | 22 +++++++---- src/event/TimeoutMonitor.hxx | 24 ++++++----- 15 files changed, 295 insertions(+), 114 deletions(-) diff --git a/configure.ac b/configure.ac index bfd7ed2ff..f7624a0f4 100644 --- a/configure.ac +++ b/configure.ac @@ -148,7 +148,6 @@ AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_CHECK_FUNCS(pipe2 accept4) MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD) MPD_OPTIONAL_FUNC(signalfd, signalfd, USE_SIGNALFD) -MPD_OPTIONAL_FUNC(epoll, epoll_create1, USE_EPOLL) AC_SEARCH_LIBS([exp], [m],, [AC_MSG_ERROR([exp() not found])]) @@ -156,6 +155,63 @@ AC_SEARCH_LIBS([exp], [m],, AC_CHECK_HEADERS(locale.h) AC_CHECK_HEADERS(valgrind/memcheck.h) +dnl --------------------------------------------------------------------------- +dnl Event loop selection +dnl --------------------------------------------------------------------------- + +MPD_OPTIONAL_FUNC_NODEF(epoll, epoll_create1) + +AC_ARG_WITH(eventloop, + AS_HELP_STRING( + [--with-eventloop=@<:@glib|internal|auto@:>@], + [specify event loop implementation (default=auto)]),, + [with_eventloop=auto]) + +AC_ARG_WITH(pollmethod, + AS_HELP_STRING( + [--with-pollmethod=@<:@epoll|auto@:>@], + [specify poll method for internal event loop (default=auto)]),, + [with_pollmethod=auto]) + +if test "x$with_eventloop" = xauto; then + if test "x$enable_epoll" = xyes; then + with_eventloop=internal + else + with_eventloop=glib + fi +fi + +case "$with_eventloop" in +glib) + AC_DEFINE(USE_GLIB_EVENTLOOP, 1, + [Define to use GLib event loop]) + ;; +internal) + AC_DEFINE(USE_INTERNAL_EVENTLOOP, 1, + [Define to use internal event loop]) + ;; +*) + AC_MSG_ERROR([unknown eventloop option: $with_eventloop]) + ;; +esac + +if test "x$with_eventloop" = xinternal; then + if test "x$with_pollmethod" = xauto; then + if test "x$enable_epoll" = xyes; then + with_pollmethod=epoll + else + AC_MSG_ERROR([no poll method is available for your platform]) + fi + fi + case "$with_pollmethod" in + epoll) + AC_DEFINE(USE_EPOLL, 1, [Define to poll sockets with epoll]) + ;; + *) + AC_MSG_ERROR([unknown pollmethod option: $with_pollmethod]) + esac +fi + dnl --------------------------------------------------------------------------- dnl Allow tools to be specifically built dnl --------------------------------------------------------------------------- @@ -1620,6 +1676,16 @@ results(soundcloud,[Soundcloud]) printf '\n\t' results(mms,[MMS]) +printf '\nEvent loop:\n\t' +case $with_eventloop in +glib) + printf 'GLib' + ;; +internal) + printf 'Internal (%s)' $with_pollmethod + ;; +esac + printf '\n\n##########################################\n\n' echo 'Generating files needed for compilation' diff --git a/m4/mpd_func.m4 b/m4/mpd_func.m4 index d12d27062..5f2bf8f3d 100644 --- a/m4/mpd_func.m4 +++ b/m4/mpd_func.m4 @@ -10,3 +10,16 @@ AC_DEFUN([MPD_OPTIONAL_FUNC], [ [AC_CHECK_FUNC([$2], [AC_DEFINE([$3], 1, [Define to use $1])],)]) ]) + +dnl MPD_OPTIONAL_FUNC_NODEF(name, func) +dnl +dnl Allow the user to enable or disable the use of a function. +dnl Works similar to MPD_OPTIONAL_FUNC, however MPD_OPTIONAL_FUNC_NODEF +dnl does not invoke AC_DEFINE when function is enabled. Shell variable +dnl enable_$name is set to "yes" instead. +AC_DEFUN([MPD_OPTIONAL_FUNC_NODEF], [ + AC_ARG_ENABLE([$1], + AS_HELP_STRING([--enable-$1], + [use the function "$1" (default: auto)]),, + [AC_CHECK_FUNC([$2], [enable_$1=yes],)]) +]) diff --git a/src/event/Call.cxx b/src/event/Call.cxx index ab1d5ffbd..7767824f9 100644 --- a/src/event/Call.cxx +++ b/src/event/Call.cxx @@ -28,7 +28,7 @@ #include class BlockingCallMonitor final -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP : DeferredMonitor #endif { @@ -40,20 +40,22 @@ class BlockingCallMonitor final bool done; public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP BlockingCallMonitor(EventLoop &loop, std::function &&_f) :f(std::move(_f)), done(false) { loop.AddCall([this](){ this->DoRun(); }); } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP BlockingCallMonitor(EventLoop &_loop, std::function &&_f) :DeferredMonitor(_loop), f(std::move(_f)), done(false) {} #endif void Run() { -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP assert(!done); Schedule(); @@ -65,13 +67,14 @@ public: mutex.unlock(); } -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP private: virtual void RunDeferred() override { DoRun(); } +#endif -#else +#ifdef USE_INTERNAL_EVENTLOOP public: #endif void DoRun() { diff --git a/src/event/DeferredMonitor.cxx b/src/event/DeferredMonitor.cxx index 4ffffaa89..40b4b0b62 100644 --- a/src/event/DeferredMonitor.cxx +++ b/src/event/DeferredMonitor.cxx @@ -24,9 +24,10 @@ void DeferredMonitor::Cancel() { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP pending = false; -#else +#endif +#ifdef USE_GLIB_EVENTLOOP const auto id = source_id.exchange(0); if (id != 0) g_source_remove(id); @@ -36,10 +37,11 @@ DeferredMonitor::Cancel() void DeferredMonitor::Schedule() { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP if (!pending.exchange(true)) fd.Write(); -#else +#endif +#ifdef USE_GLIB_EVENTLOOP const unsigned id = loop.AddIdle(Callback, this); const auto old_id = source_id.exchange(id); if (old_id != 0) @@ -47,7 +49,7 @@ DeferredMonitor::Schedule() #endif } -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP bool DeferredMonitor::OnSocketReady(unsigned) @@ -60,7 +62,9 @@ DeferredMonitor::OnSocketReady(unsigned) return true; } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP void DeferredMonitor::Run() diff --git a/src/event/DeferredMonitor.hxx b/src/event/DeferredMonitor.hxx index 2380fb66f..d4c812e44 100644 --- a/src/event/DeferredMonitor.hxx +++ b/src/event/DeferredMonitor.hxx @@ -23,10 +23,12 @@ #include "check.h" #include "Compiler.h" -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP #include "SocketMonitor.hxx" #include "WakeFD.hxx" -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP #include #endif @@ -38,44 +40,51 @@ class EventLoop; * Defer execution of an event into an #EventLoop. */ class DeferredMonitor -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP : private SocketMonitor #endif { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP std::atomic_bool pending; WakeFD fd; -#else - EventLoop &loop; +#endif +#ifdef USE_GLIB_EVENTLOOP + EventLoop &loop; std::atomic source_id; #endif public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP DeferredMonitor(EventLoop &_loop) :SocketMonitor(_loop), pending(false) { SocketMonitor::Open(fd.Get()); SocketMonitor::Schedule(SocketMonitor::READ); } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP DeferredMonitor(EventLoop &_loop) :loop(_loop), source_id(0) {} #endif ~DeferredMonitor() { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP /* avoid closing the WakeFD twice */ SocketMonitor::Steal(); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP Cancel(); #endif } EventLoop &GetEventLoop() { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP return SocketMonitor::GetEventLoop(); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP return loop; #endif } @@ -87,9 +96,11 @@ protected: virtual void RunDeferred() = 0; private: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP virtual bool OnSocketReady(unsigned flags) override final; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP void Run(); static gboolean Callback(gpointer data); #endif diff --git a/src/event/IdleMonitor.cxx b/src/event/IdleMonitor.cxx index c99c66b26..8d25407b5 100644 --- a/src/event/IdleMonitor.cxx +++ b/src/event/IdleMonitor.cxx @@ -29,10 +29,11 @@ IdleMonitor::Cancel() if (!IsActive()) return; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP active = false; loop.RemoveIdle(*this); -#else +#endif +#ifdef USE_GLIB_EVENTLOOP g_source_remove(source_id); source_id = 0; #endif @@ -47,10 +48,11 @@ IdleMonitor::Schedule() /* already scheduled */ return; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP active = true; loop.AddIdle(*this); -#else +#endif +#ifdef USE_GLIB_EVENTLOOP source_id = loop.AddIdle(Callback, this); #endif } @@ -60,10 +62,11 @@ IdleMonitor::Run() { assert(loop.IsInside()); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP assert(active); active = false; -#else +#endif +#ifdef USE_GLIB_EVENTLOOP assert(source_id != 0); source_id = 0; #endif @@ -71,7 +74,7 @@ IdleMonitor::Run() OnIdle(); } -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP gboolean IdleMonitor::Callback(gpointer data) diff --git a/src/event/IdleMonitor.hxx b/src/event/IdleMonitor.hxx index c8e79eb1d..b040915e7 100644 --- a/src/event/IdleMonitor.hxx +++ b/src/event/IdleMonitor.hxx @@ -22,7 +22,7 @@ #include "check.h" -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP #include #endif @@ -34,23 +34,27 @@ class EventLoop; * methods must be run from EventLoop's thread. */ class IdleMonitor { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP friend class EventLoop; #endif EventLoop &loop; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP bool active; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP guint source_id; #endif public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP IdleMonitor(EventLoop &_loop) :loop(_loop), active(false) {} -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP IdleMonitor(EventLoop &_loop) :loop(_loop), source_id(0) {} #endif @@ -64,9 +68,11 @@ public: } bool IsActive() const { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP return active; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP return source_id != 0; #endif } @@ -79,7 +85,7 @@ protected: private: void Run(); -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP static gboolean Callback(gpointer data); #endif }; diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index 5aa24aea2..ccba7bb45 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "Loop.hxx" -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP #include "system/Clock.hxx" #include "TimeoutMonitor.hxx" @@ -33,7 +33,9 @@ EventLoop::EventLoop(Default) :SocketMonitor(*this), now_ms(::MonotonicClockMS()), quit(false), +#ifdef USE_EPOLL n_events(0), +#endif thread(ThreadId::Null()) { SocketMonitor::Open(wake_fd.Get()); @@ -61,16 +63,20 @@ EventLoop::Break() void EventLoop::Abandon(SocketMonitor &m) { +#ifdef USE_EPOLL for (unsigned i = 0, n = n_events; i < n; ++i) if (events[i].data.ptr == &m) events[i].events = 0; +#endif } bool EventLoop::RemoveFD(int _fd, SocketMonitor &m) { +#ifdef USE_EPOLL Abandon(m); return epoll.Remove(_fd); +#endif } void @@ -115,7 +121,7 @@ EventLoop::Run() assert(thread.IsNull()); thread = ThreadId::GetCurrent(); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP assert(!quit); do { @@ -162,6 +168,7 @@ EventLoop::Run() timeout */ continue; +#ifdef USE_EPOLL /* wait for new event */ const int n = epoll.Wait(events, MAX_EVENTS, timeout_ms); @@ -186,15 +193,19 @@ EventLoop::Run() } n_events = 0; +#endif } while (!quit); -#else + +#endif + +#ifdef USE_GLIB_EVENTLOOP g_main_loop_run(loop); #endif assert(thread.IsInside()); } -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP void EventLoop::AddCall(std::function &&f) @@ -229,7 +240,9 @@ EventLoop::OnSocketReady(gcc_unused unsigned flags) return true; } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP guint EventLoop::AddIdle(GSourceFunc function, gpointer data) diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index 223527853..f188c7cc0 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -24,8 +24,11 @@ #include "thread/Id.hxx" #include "Compiler.h" +#ifdef USE_INTERNAL_EVENTLOOP #ifdef USE_EPOLL #include "system/EPollFD.hxx" +#endif + #include "thread/Mutex.hxx" #include "WakeFD.hxx" #include "SocketMonitor.hxx" @@ -33,11 +36,13 @@ #include #include #include -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP #include #endif -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP class TimeoutMonitor; class IdleMonitor; class SocketMonitor; @@ -55,11 +60,11 @@ class SocketMonitor; * @see SocketMonitor, MultiSocketMonitor, TimeoutMonitor, IdleMonitor */ class EventLoop final -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP : private SocketMonitor #endif { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP struct TimerRecord { /** * Projected monotonic_clock_ms() value when this @@ -82,8 +87,6 @@ class EventLoop final } }; - EPollFD epoll; - WakeFD wake_fd; std::multiset timers; @@ -96,10 +99,16 @@ class EventLoop final bool quit; +#ifdef USE_EPOLL + EPollFD epoll; static constexpr unsigned MAX_EVENTS = 16; unsigned n_events; epoll_event events[MAX_EVENTS]; -#else +#endif + +#endif + +#ifdef USE_GLIB_EVENTLOOP GMainContext *context; GMainLoop *loop; #endif @@ -110,7 +119,7 @@ class EventLoop final ThreadId thread; public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP struct Default {}; EventLoop(Default dummy=Default()); @@ -131,11 +140,15 @@ public: void Break(); bool AddFD(int _fd, unsigned flags, SocketMonitor &m) { +#ifdef USE_EPOLL return epoll.Add(_fd, flags, &m); +#endif } bool ModifyFD(int _fd, unsigned flags, SocketMonitor &m) { +#ifdef USE_EPOLL return epoll.Modify(_fd, flags, &m); +#endif } /** @@ -165,7 +178,9 @@ private: virtual bool OnSocketReady(unsigned flags) override; public: -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP EventLoop() :context(g_main_context_new()), loop(g_main_loop_new(context, false)), diff --git a/src/event/MultiSocketMonitor.cxx b/src/event/MultiSocketMonitor.cxx index bd1aa6fef..f26ab6c28 100644 --- a/src/event/MultiSocketMonitor.cxx +++ b/src/event/MultiSocketMonitor.cxx @@ -25,7 +25,7 @@ #include -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP MultiSocketMonitor::MultiSocketMonitor(EventLoop &_loop) :IdleMonitor(_loop), TimeoutMonitor(_loop), ready(false) { @@ -65,7 +65,9 @@ MultiSocketMonitor::OnIdle() } } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP /** * The vtable for our GSource implementation. Unfortunately, we diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx index 7ca666246..fed6929c1 100644 --- a/src/event/MultiSocketMonitor.hxx +++ b/src/event/MultiSocketMonitor.hxx @@ -23,11 +23,13 @@ #include "check.h" #include "Compiler.h" -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP #include "IdleMonitor.hxx" #include "TimeoutMonitor.hxx" #include "SocketMonitor.hxx" -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP #include #endif @@ -53,11 +55,11 @@ class EventLoop; * DispatchSockets() will be called if at least one socket is ready. */ class MultiSocketMonitor -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP : private IdleMonitor, private TimeoutMonitor #endif { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP class SingleFD final : public SocketMonitor { MultiSocketMonitor &multi; @@ -102,7 +104,9 @@ class MultiSocketMonitor friend class SingleFD; bool ready, refresh; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP struct Source { GSource base; @@ -141,12 +145,14 @@ class MultiSocketMonitor std::forward_list fds; public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP static constexpr unsigned READ = SocketMonitor::READ; static constexpr unsigned WRITE = SocketMonitor::WRITE; static constexpr unsigned ERROR = SocketMonitor::ERROR; static constexpr unsigned HANGUP = SocketMonitor::HANGUP; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP static constexpr unsigned READ = G_IO_IN; static constexpr unsigned WRITE = G_IO_OUT; static constexpr unsigned ERROR = G_IO_ERR; @@ -156,16 +162,18 @@ public: MultiSocketMonitor(EventLoop &_loop); ~MultiSocketMonitor(); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP using IdleMonitor::GetEventLoop; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP EventLoop &GetEventLoop() { return loop; } #endif public: -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP gcc_pure uint64_t GetTime() const { return g_source_get_time(&source->base); @@ -173,10 +181,12 @@ public: #endif void InvalidateSockets() { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP refresh = true; IdleMonitor::Schedule(); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP /* no-op because GLib always calls the GSource's "prepare" method before each poll() anyway */ #endif @@ -184,7 +194,7 @@ public: void AddSocket(int fd, unsigned events) { fds.emplace_front(*this, fd, events); -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP g_source_add_poll(&source->base, &fds.front().pfd); #endif } @@ -201,9 +211,11 @@ public: i->SetEvents(events); prev = i; } else { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP i->Steal(); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP g_source_remove_poll(&source->base, &i->pfd); #endif fds.erase_after(prev); @@ -218,7 +230,7 @@ protected: virtual int PrepareSockets() = 0; virtual void DispatchSockets() = 0; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP private: void SetReady() { ready = true; @@ -234,7 +246,9 @@ private: virtual void OnIdle() final; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP public: /* GSource callbacks */ static gboolean Prepare(GSource *source, gint *timeout_r); diff --git a/src/event/SocketMonitor.cxx b/src/event/SocketMonitor.cxx index 2b97059f7..fdef0acb6 100644 --- a/src/event/SocketMonitor.cxx +++ b/src/event/SocketMonitor.cxx @@ -32,7 +32,7 @@ #include #endif -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP void SocketMonitor::Dispatch(unsigned flags) @@ -43,7 +43,9 @@ SocketMonitor::Dispatch(unsigned flags) Cancel(); } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP /* * GSource methods @@ -113,14 +115,14 @@ void SocketMonitor::Open(int _fd) { assert(fd < 0); -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP assert(source == nullptr); #endif assert(_fd >= 0); fd = _fd; -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP poll = {fd, 0, 0}; source = (Source *)g_source_new(&socket_monitor_source_funcs, @@ -142,7 +144,7 @@ SocketMonitor::Steal() int result = fd; fd = -1; -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP g_source_destroy(&source->base); g_source_unref(&source->base); source = nullptr; @@ -156,7 +158,7 @@ SocketMonitor::Abandon() { assert(IsDefined()); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP fd = -1; loop.Abandon(*this); #else @@ -178,7 +180,7 @@ SocketMonitor::Schedule(unsigned flags) if (flags == GetScheduledFlags()) return; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP if (scheduled_flags == 0) loop.AddFD(fd, flags, *this); else if (flags == 0) @@ -187,7 +189,9 @@ SocketMonitor::Schedule(unsigned flags) loop.ModifyFD(fd, flags, *this); scheduled_flags = flags; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP poll.events = flags; poll.revents &= flags; diff --git a/src/event/SocketMonitor.hxx b/src/event/SocketMonitor.hxx index ff2864d63..4d3e5aea2 100644 --- a/src/event/SocketMonitor.hxx +++ b/src/event/SocketMonitor.hxx @@ -22,9 +22,13 @@ #include "check.h" +#ifdef USE_INTERNAL_EVENTLOOP #ifdef USE_EPOLL #include -#else +#endif +#endif + +#ifdef USE_GLIB_EVENTLOOP #include #endif @@ -50,8 +54,7 @@ class EventLoop; * any of the subscribed events are ready. */ class SocketMonitor { -#ifdef USE_EPOLL -#else +#ifdef USE_GLIB_EVENTLOOP struct Source { GSource base; @@ -62,38 +65,46 @@ class SocketMonitor { int fd; EventLoop &loop; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP /** * A bit mask of events that is currently registered in the EventLoop. */ unsigned scheduled_flags; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP Source *source; GPollFD poll; #endif public: +#ifdef USE_INTERNAL_EVENTLOOP #ifdef USE_EPOLL static constexpr unsigned READ = EPOLLIN; static constexpr unsigned WRITE = EPOLLOUT; static constexpr unsigned ERROR = EPOLLERR; static constexpr unsigned HANGUP = EPOLLHUP; -#else +#endif +#endif + +#ifdef USE_GLIB_EVENTLOOP static constexpr unsigned READ = G_IO_IN; static constexpr unsigned WRITE = G_IO_OUT; static constexpr unsigned ERROR = G_IO_ERR; static constexpr unsigned HANGUP = G_IO_HUP; -#endif +#endif typedef std::make_signed::type ssize_t; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP SocketMonitor(EventLoop &_loop) :fd(-1), loop(_loop), scheduled_flags(0) {} SocketMonitor(int _fd, EventLoop &_loop) :fd(_fd), loop(_loop), scheduled_flags(0) {} -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP SocketMonitor(EventLoop &_loop) :fd(-1), loop(_loop), source(nullptr) {} @@ -134,9 +145,11 @@ public: unsigned GetScheduledFlags() const { assert(IsDefined()); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP return scheduled_flags; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP return poll.events; #endif } @@ -173,9 +186,11 @@ protected: virtual bool OnSocketReady(unsigned flags) = 0; public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP void Dispatch(unsigned flags); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP /* GSource callbacks */ static gboolean Prepare(GSource *source, gint *timeout_r); static gboolean Check(GSource *source); diff --git a/src/event/TimeoutMonitor.cxx b/src/event/TimeoutMonitor.cxx index cffad6b92..3d7d46324 100644 --- a/src/event/TimeoutMonitor.cxx +++ b/src/event/TimeoutMonitor.cxx @@ -25,10 +25,12 @@ void TimeoutMonitor::Cancel() { if (IsActive()) { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP active = false; loop.CancelTimer(*this); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP g_source_destroy(source); g_source_unref(source); source = nullptr; @@ -41,10 +43,12 @@ TimeoutMonitor::Schedule(unsigned ms) { Cancel(); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP active = true; loop.AddTimer(*this, ms); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP source = loop.AddTimeout(ms, Callback, this); #endif } @@ -54,9 +58,11 @@ TimeoutMonitor::ScheduleSeconds(unsigned s) { Cancel(); -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP Schedule(s * 1000u); -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP source = loop.AddTimeoutSeconds(s, Callback, this); #endif } @@ -64,14 +70,14 @@ TimeoutMonitor::ScheduleSeconds(unsigned s) void TimeoutMonitor::Run() { -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP Cancel(); #endif OnTimeout(); } -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP gboolean TimeoutMonitor::Callback(gpointer data) diff --git a/src/event/TimeoutMonitor.hxx b/src/event/TimeoutMonitor.hxx index aa2bbea39..568aa27ef 100644 --- a/src/event/TimeoutMonitor.hxx +++ b/src/event/TimeoutMonitor.hxx @@ -22,7 +22,7 @@ #include "check.h" -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP #include #endif @@ -33,24 +33,28 @@ class EventLoop; * or Cancel() to cancel it. */ class TimeoutMonitor { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP friend class EventLoop; #endif EventLoop &loop; -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP bool active; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP GSource *source; #endif public: -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP TimeoutMonitor(EventLoop &_loop) :loop(_loop), active(false) { } -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP TimeoutMonitor(EventLoop &_loop) :loop(_loop), source(nullptr) {} #endif @@ -64,9 +68,11 @@ public: } bool IsActive() const { -#ifdef USE_EPOLL +#ifdef USE_INTERNAL_EVENTLOOP return active; -#else +#endif + +#ifdef USE_GLIB_EVENTLOOP return source != nullptr; #endif } @@ -81,7 +87,7 @@ protected: private: void Run(); -#ifndef USE_EPOLL +#ifdef USE_GLIB_EVENTLOOP static gboolean Callback(gpointer data); #endif };