You need to sign in or sign up before continuing.
Commit 46bab7e4 authored by Denis Krjuchkov's avatar Denis Krjuchkov

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.
parent 22fb49fa
...@@ -148,7 +148,6 @@ AC_SEARCH_LIBS([gethostbyname], [nsl]) ...@@ -148,7 +148,6 @@ AC_SEARCH_LIBS([gethostbyname], [nsl])
AC_CHECK_FUNCS(pipe2 accept4) AC_CHECK_FUNCS(pipe2 accept4)
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD) MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)
MPD_OPTIONAL_FUNC(signalfd, signalfd, USE_SIGNALFD) MPD_OPTIONAL_FUNC(signalfd, signalfd, USE_SIGNALFD)
MPD_OPTIONAL_FUNC(epoll, epoll_create1, USE_EPOLL)
AC_SEARCH_LIBS([exp], [m],, AC_SEARCH_LIBS([exp], [m],,
[AC_MSG_ERROR([exp() not found])]) [AC_MSG_ERROR([exp() not found])])
...@@ -157,6 +156,63 @@ AC_CHECK_HEADERS(locale.h) ...@@ -157,6 +156,63 @@ AC_CHECK_HEADERS(locale.h)
AC_CHECK_HEADERS(valgrind/memcheck.h) AC_CHECK_HEADERS(valgrind/memcheck.h)
dnl --------------------------------------------------------------------------- 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 Allow tools to be specifically built
dnl --------------------------------------------------------------------------- dnl ---------------------------------------------------------------------------
...@@ -1620,6 +1676,16 @@ results(soundcloud,[Soundcloud]) ...@@ -1620,6 +1676,16 @@ results(soundcloud,[Soundcloud])
printf '\n\t' printf '\n\t'
results(mms,[MMS]) 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' printf '\n\n##########################################\n\n'
echo 'Generating files needed for compilation' echo 'Generating files needed for compilation'
......
...@@ -10,3 +10,16 @@ AC_DEFUN([MPD_OPTIONAL_FUNC], [ ...@@ -10,3 +10,16 @@ AC_DEFUN([MPD_OPTIONAL_FUNC], [
[AC_CHECK_FUNC([$2], [AC_CHECK_FUNC([$2],
[AC_DEFINE([$3], 1, [Define to use $1])],)]) [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],)])
])
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <assert.h> #include <assert.h>
class BlockingCallMonitor final class BlockingCallMonitor final
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
: DeferredMonitor : DeferredMonitor
#endif #endif
{ {
...@@ -40,20 +40,22 @@ class BlockingCallMonitor final ...@@ -40,20 +40,22 @@ class BlockingCallMonitor final
bool done; bool done;
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
BlockingCallMonitor(EventLoop &loop, std::function<void()> &&_f) BlockingCallMonitor(EventLoop &loop, std::function<void()> &&_f)
:f(std::move(_f)), done(false) { :f(std::move(_f)), done(false) {
loop.AddCall([this](){ loop.AddCall([this](){
this->DoRun(); this->DoRun();
}); });
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
BlockingCallMonitor(EventLoop &_loop, std::function<void()> &&_f) BlockingCallMonitor(EventLoop &_loop, std::function<void()> &&_f)
:DeferredMonitor(_loop), f(std::move(_f)), done(false) {} :DeferredMonitor(_loop), f(std::move(_f)), done(false) {}
#endif #endif
void Run() { void Run() {
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
assert(!done); assert(!done);
Schedule(); Schedule();
...@@ -65,13 +67,14 @@ public: ...@@ -65,13 +67,14 @@ public:
mutex.unlock(); mutex.unlock();
} }
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
private: private:
virtual void RunDeferred() override { virtual void RunDeferred() override {
DoRun(); DoRun();
} }
#endif
#else #ifdef USE_INTERNAL_EVENTLOOP
public: public:
#endif #endif
void DoRun() { void DoRun() {
......
...@@ -24,9 +24,10 @@ ...@@ -24,9 +24,10 @@
void void
DeferredMonitor::Cancel() DeferredMonitor::Cancel()
{ {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
pending = false; pending = false;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
const auto id = source_id.exchange(0); const auto id = source_id.exchange(0);
if (id != 0) if (id != 0)
g_source_remove(id); g_source_remove(id);
...@@ -36,10 +37,11 @@ DeferredMonitor::Cancel() ...@@ -36,10 +37,11 @@ DeferredMonitor::Cancel()
void void
DeferredMonitor::Schedule() DeferredMonitor::Schedule()
{ {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
if (!pending.exchange(true)) if (!pending.exchange(true))
fd.Write(); fd.Write();
#else #endif
#ifdef USE_GLIB_EVENTLOOP
const unsigned id = loop.AddIdle(Callback, this); const unsigned id = loop.AddIdle(Callback, this);
const auto old_id = source_id.exchange(id); const auto old_id = source_id.exchange(id);
if (old_id != 0) if (old_id != 0)
...@@ -47,7 +49,7 @@ DeferredMonitor::Schedule() ...@@ -47,7 +49,7 @@ DeferredMonitor::Schedule()
#endif #endif
} }
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
bool bool
DeferredMonitor::OnSocketReady(unsigned) DeferredMonitor::OnSocketReady(unsigned)
...@@ -60,7 +62,9 @@ DeferredMonitor::OnSocketReady(unsigned) ...@@ -60,7 +62,9 @@ DeferredMonitor::OnSocketReady(unsigned)
return true; return true;
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
void void
DeferredMonitor::Run() DeferredMonitor::Run()
......
...@@ -23,10 +23,12 @@ ...@@ -23,10 +23,12 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
#include "SocketMonitor.hxx" #include "SocketMonitor.hxx"
#include "WakeFD.hxx" #include "WakeFD.hxx"
#else #endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h> #include <glib.h>
#endif #endif
...@@ -38,44 +40,51 @@ class EventLoop; ...@@ -38,44 +40,51 @@ class EventLoop;
* Defer execution of an event into an #EventLoop. * Defer execution of an event into an #EventLoop.
*/ */
class DeferredMonitor class DeferredMonitor
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
: private SocketMonitor : private SocketMonitor
#endif #endif
{ {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
std::atomic_bool pending; std::atomic_bool pending;
WakeFD fd; WakeFD fd;
#else #endif
EventLoop &loop;
#ifdef USE_GLIB_EVENTLOOP
EventLoop &loop;
std::atomic<guint> source_id; std::atomic<guint> source_id;
#endif #endif
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
DeferredMonitor(EventLoop &_loop) DeferredMonitor(EventLoop &_loop)
:SocketMonitor(_loop), pending(false) { :SocketMonitor(_loop), pending(false) {
SocketMonitor::Open(fd.Get()); SocketMonitor::Open(fd.Get());
SocketMonitor::Schedule(SocketMonitor::READ); SocketMonitor::Schedule(SocketMonitor::READ);
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
DeferredMonitor(EventLoop &_loop) DeferredMonitor(EventLoop &_loop)
:loop(_loop), source_id(0) {} :loop(_loop), source_id(0) {}
#endif #endif
~DeferredMonitor() { ~DeferredMonitor() {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
/* avoid closing the WakeFD twice */ /* avoid closing the WakeFD twice */
SocketMonitor::Steal(); SocketMonitor::Steal();
#else #endif
#ifdef USE_GLIB_EVENTLOOP
Cancel(); Cancel();
#endif #endif
} }
EventLoop &GetEventLoop() { EventLoop &GetEventLoop() {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
return SocketMonitor::GetEventLoop(); return SocketMonitor::GetEventLoop();
#else #endif
#ifdef USE_GLIB_EVENTLOOP
return loop; return loop;
#endif #endif
} }
...@@ -87,9 +96,11 @@ protected: ...@@ -87,9 +96,11 @@ protected:
virtual void RunDeferred() = 0; virtual void RunDeferred() = 0;
private: private:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
virtual bool OnSocketReady(unsigned flags) override final; virtual bool OnSocketReady(unsigned flags) override final;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
void Run(); void Run();
static gboolean Callback(gpointer data); static gboolean Callback(gpointer data);
#endif #endif
......
...@@ -29,10 +29,11 @@ IdleMonitor::Cancel() ...@@ -29,10 +29,11 @@ IdleMonitor::Cancel()
if (!IsActive()) if (!IsActive())
return; return;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
active = false; active = false;
loop.RemoveIdle(*this); loop.RemoveIdle(*this);
#else #endif
#ifdef USE_GLIB_EVENTLOOP
g_source_remove(source_id); g_source_remove(source_id);
source_id = 0; source_id = 0;
#endif #endif
...@@ -47,10 +48,11 @@ IdleMonitor::Schedule() ...@@ -47,10 +48,11 @@ IdleMonitor::Schedule()
/* already scheduled */ /* already scheduled */
return; return;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
active = true; active = true;
loop.AddIdle(*this); loop.AddIdle(*this);
#else #endif
#ifdef USE_GLIB_EVENTLOOP
source_id = loop.AddIdle(Callback, this); source_id = loop.AddIdle(Callback, this);
#endif #endif
} }
...@@ -60,10 +62,11 @@ IdleMonitor::Run() ...@@ -60,10 +62,11 @@ IdleMonitor::Run()
{ {
assert(loop.IsInside()); assert(loop.IsInside());
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
assert(active); assert(active);
active = false; active = false;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
assert(source_id != 0); assert(source_id != 0);
source_id = 0; source_id = 0;
#endif #endif
...@@ -71,7 +74,7 @@ IdleMonitor::Run() ...@@ -71,7 +74,7 @@ IdleMonitor::Run()
OnIdle(); OnIdle();
} }
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
gboolean gboolean
IdleMonitor::Callback(gpointer data) IdleMonitor::Callback(gpointer data)
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "check.h" #include "check.h"
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
#include <glib.h> #include <glib.h>
#endif #endif
...@@ -34,23 +34,27 @@ class EventLoop; ...@@ -34,23 +34,27 @@ class EventLoop;
* methods must be run from EventLoop's thread. * methods must be run from EventLoop's thread.
*/ */
class IdleMonitor { class IdleMonitor {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
friend class EventLoop; friend class EventLoop;
#endif #endif
EventLoop &loop; EventLoop &loop;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
bool active; bool active;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
guint source_id; guint source_id;
#endif #endif
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
IdleMonitor(EventLoop &_loop) IdleMonitor(EventLoop &_loop)
:loop(_loop), active(false) {} :loop(_loop), active(false) {}
#else #endif
#ifdef USE_GLIB_EVENTLOOP
IdleMonitor(EventLoop &_loop) IdleMonitor(EventLoop &_loop)
:loop(_loop), source_id(0) {} :loop(_loop), source_id(0) {}
#endif #endif
...@@ -64,9 +68,11 @@ public: ...@@ -64,9 +68,11 @@ public:
} }
bool IsActive() const { bool IsActive() const {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
return active; return active;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
return source_id != 0; return source_id != 0;
#endif #endif
} }
...@@ -79,7 +85,7 @@ protected: ...@@ -79,7 +85,7 @@ protected:
private: private:
void Run(); void Run();
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
static gboolean Callback(gpointer data); static gboolean Callback(gpointer data);
#endif #endif
}; };
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "Loop.hxx" #include "Loop.hxx"
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
#include "system/Clock.hxx" #include "system/Clock.hxx"
#include "TimeoutMonitor.hxx" #include "TimeoutMonitor.hxx"
...@@ -33,7 +33,9 @@ EventLoop::EventLoop(Default) ...@@ -33,7 +33,9 @@ EventLoop::EventLoop(Default)
:SocketMonitor(*this), :SocketMonitor(*this),
now_ms(::MonotonicClockMS()), now_ms(::MonotonicClockMS()),
quit(false), quit(false),
#ifdef USE_EPOLL
n_events(0), n_events(0),
#endif
thread(ThreadId::Null()) thread(ThreadId::Null())
{ {
SocketMonitor::Open(wake_fd.Get()); SocketMonitor::Open(wake_fd.Get());
...@@ -61,16 +63,20 @@ EventLoop::Break() ...@@ -61,16 +63,20 @@ EventLoop::Break()
void void
EventLoop::Abandon(SocketMonitor &m) EventLoop::Abandon(SocketMonitor &m)
{ {
#ifdef USE_EPOLL
for (unsigned i = 0, n = n_events; i < n; ++i) for (unsigned i = 0, n = n_events; i < n; ++i)
if (events[i].data.ptr == &m) if (events[i].data.ptr == &m)
events[i].events = 0; events[i].events = 0;
#endif
} }
bool bool
EventLoop::RemoveFD(int _fd, SocketMonitor &m) EventLoop::RemoveFD(int _fd, SocketMonitor &m)
{ {
#ifdef USE_EPOLL
Abandon(m); Abandon(m);
return epoll.Remove(_fd); return epoll.Remove(_fd);
#endif
} }
void void
...@@ -115,7 +121,7 @@ EventLoop::Run() ...@@ -115,7 +121,7 @@ EventLoop::Run()
assert(thread.IsNull()); assert(thread.IsNull());
thread = ThreadId::GetCurrent(); thread = ThreadId::GetCurrent();
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
assert(!quit); assert(!quit);
do { do {
...@@ -162,6 +168,7 @@ EventLoop::Run() ...@@ -162,6 +168,7 @@ EventLoop::Run()
timeout */ timeout */
continue; continue;
#ifdef USE_EPOLL
/* wait for new event */ /* wait for new event */
const int n = epoll.Wait(events, MAX_EVENTS, timeout_ms); const int n = epoll.Wait(events, MAX_EVENTS, timeout_ms);
...@@ -186,15 +193,19 @@ EventLoop::Run() ...@@ -186,15 +193,19 @@ EventLoop::Run()
} }
n_events = 0; n_events = 0;
#endif
} while (!quit); } while (!quit);
#else
#endif
#ifdef USE_GLIB_EVENTLOOP
g_main_loop_run(loop); g_main_loop_run(loop);
#endif #endif
assert(thread.IsInside()); assert(thread.IsInside());
} }
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
void void
EventLoop::AddCall(std::function<void()> &&f) EventLoop::AddCall(std::function<void()> &&f)
...@@ -229,7 +240,9 @@ EventLoop::OnSocketReady(gcc_unused unsigned flags) ...@@ -229,7 +240,9 @@ EventLoop::OnSocketReady(gcc_unused unsigned flags)
return true; return true;
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
guint guint
EventLoop::AddIdle(GSourceFunc function, gpointer data) EventLoop::AddIdle(GSourceFunc function, gpointer data)
......
...@@ -24,8 +24,11 @@ ...@@ -24,8 +24,11 @@
#include "thread/Id.hxx" #include "thread/Id.hxx"
#include "Compiler.h" #include "Compiler.h"
#ifdef USE_INTERNAL_EVENTLOOP
#ifdef USE_EPOLL #ifdef USE_EPOLL
#include "system/EPollFD.hxx" #include "system/EPollFD.hxx"
#endif
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "WakeFD.hxx" #include "WakeFD.hxx"
#include "SocketMonitor.hxx" #include "SocketMonitor.hxx"
...@@ -33,11 +36,13 @@ ...@@ -33,11 +36,13 @@
#include <functional> #include <functional>
#include <list> #include <list>
#include <set> #include <set>
#else #endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h> #include <glib.h>
#endif #endif
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
class TimeoutMonitor; class TimeoutMonitor;
class IdleMonitor; class IdleMonitor;
class SocketMonitor; class SocketMonitor;
...@@ -55,11 +60,11 @@ class SocketMonitor; ...@@ -55,11 +60,11 @@ class SocketMonitor;
* @see SocketMonitor, MultiSocketMonitor, TimeoutMonitor, IdleMonitor * @see SocketMonitor, MultiSocketMonitor, TimeoutMonitor, IdleMonitor
*/ */
class EventLoop final class EventLoop final
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
: private SocketMonitor : private SocketMonitor
#endif #endif
{ {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
struct TimerRecord { struct TimerRecord {
/** /**
* Projected monotonic_clock_ms() value when this * Projected monotonic_clock_ms() value when this
...@@ -82,8 +87,6 @@ class EventLoop final ...@@ -82,8 +87,6 @@ class EventLoop final
} }
}; };
EPollFD epoll;
WakeFD wake_fd; WakeFD wake_fd;
std::multiset<TimerRecord> timers; std::multiset<TimerRecord> timers;
...@@ -96,10 +99,16 @@ class EventLoop final ...@@ -96,10 +99,16 @@ class EventLoop final
bool quit; bool quit;
#ifdef USE_EPOLL
EPollFD epoll;
static constexpr unsigned MAX_EVENTS = 16; static constexpr unsigned MAX_EVENTS = 16;
unsigned n_events; unsigned n_events;
epoll_event events[MAX_EVENTS]; epoll_event events[MAX_EVENTS];
#else #endif
#endif
#ifdef USE_GLIB_EVENTLOOP
GMainContext *context; GMainContext *context;
GMainLoop *loop; GMainLoop *loop;
#endif #endif
...@@ -110,7 +119,7 @@ class EventLoop final ...@@ -110,7 +119,7 @@ class EventLoop final
ThreadId thread; ThreadId thread;
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
struct Default {}; struct Default {};
EventLoop(Default dummy=Default()); EventLoop(Default dummy=Default());
...@@ -131,11 +140,15 @@ public: ...@@ -131,11 +140,15 @@ public:
void Break(); void Break();
bool AddFD(int _fd, unsigned flags, SocketMonitor &m) { bool AddFD(int _fd, unsigned flags, SocketMonitor &m) {
#ifdef USE_EPOLL
return epoll.Add(_fd, flags, &m); return epoll.Add(_fd, flags, &m);
#endif
} }
bool ModifyFD(int _fd, unsigned flags, SocketMonitor &m) { bool ModifyFD(int _fd, unsigned flags, SocketMonitor &m) {
#ifdef USE_EPOLL
return epoll.Modify(_fd, flags, &m); return epoll.Modify(_fd, flags, &m);
#endif
} }
/** /**
...@@ -165,7 +178,9 @@ private: ...@@ -165,7 +178,9 @@ private:
virtual bool OnSocketReady(unsigned flags) override; virtual bool OnSocketReady(unsigned flags) override;
public: public:
#else #endif
#ifdef USE_GLIB_EVENTLOOP
EventLoop() EventLoop()
:context(g_main_context_new()), :context(g_main_context_new()),
loop(g_main_loop_new(context, false)), loop(g_main_loop_new(context, false)),
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <assert.h> #include <assert.h>
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
MultiSocketMonitor::MultiSocketMonitor(EventLoop &_loop) MultiSocketMonitor::MultiSocketMonitor(EventLoop &_loop)
:IdleMonitor(_loop), TimeoutMonitor(_loop), ready(false) { :IdleMonitor(_loop), TimeoutMonitor(_loop), ready(false) {
...@@ -65,7 +65,9 @@ MultiSocketMonitor::OnIdle() ...@@ -65,7 +65,9 @@ MultiSocketMonitor::OnIdle()
} }
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
/** /**
* The vtable for our GSource implementation. Unfortunately, we * The vtable for our GSource implementation. Unfortunately, we
......
...@@ -23,11 +23,13 @@ ...@@ -23,11 +23,13 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
#include "IdleMonitor.hxx" #include "IdleMonitor.hxx"
#include "TimeoutMonitor.hxx" #include "TimeoutMonitor.hxx"
#include "SocketMonitor.hxx" #include "SocketMonitor.hxx"
#else #endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h> #include <glib.h>
#endif #endif
...@@ -53,11 +55,11 @@ class EventLoop; ...@@ -53,11 +55,11 @@ class EventLoop;
* DispatchSockets() will be called if at least one socket is ready. * DispatchSockets() will be called if at least one socket is ready.
*/ */
class MultiSocketMonitor class MultiSocketMonitor
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
: private IdleMonitor, private TimeoutMonitor : private IdleMonitor, private TimeoutMonitor
#endif #endif
{ {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
class SingleFD final : public SocketMonitor { class SingleFD final : public SocketMonitor {
MultiSocketMonitor &multi; MultiSocketMonitor &multi;
...@@ -102,7 +104,9 @@ class MultiSocketMonitor ...@@ -102,7 +104,9 @@ class MultiSocketMonitor
friend class SingleFD; friend class SingleFD;
bool ready, refresh; bool ready, refresh;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
struct Source { struct Source {
GSource base; GSource base;
...@@ -141,12 +145,14 @@ class MultiSocketMonitor ...@@ -141,12 +145,14 @@ class MultiSocketMonitor
std::forward_list<SingleFD> fds; std::forward_list<SingleFD> fds;
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
static constexpr unsigned READ = SocketMonitor::READ; static constexpr unsigned READ = SocketMonitor::READ;
static constexpr unsigned WRITE = SocketMonitor::WRITE; static constexpr unsigned WRITE = SocketMonitor::WRITE;
static constexpr unsigned ERROR = SocketMonitor::ERROR; static constexpr unsigned ERROR = SocketMonitor::ERROR;
static constexpr unsigned HANGUP = SocketMonitor::HANGUP; static constexpr unsigned HANGUP = SocketMonitor::HANGUP;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
static constexpr unsigned READ = G_IO_IN; static constexpr unsigned READ = G_IO_IN;
static constexpr unsigned WRITE = G_IO_OUT; static constexpr unsigned WRITE = G_IO_OUT;
static constexpr unsigned ERROR = G_IO_ERR; static constexpr unsigned ERROR = G_IO_ERR;
...@@ -156,16 +162,18 @@ public: ...@@ -156,16 +162,18 @@ public:
MultiSocketMonitor(EventLoop &_loop); MultiSocketMonitor(EventLoop &_loop);
~MultiSocketMonitor(); ~MultiSocketMonitor();
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
using IdleMonitor::GetEventLoop; using IdleMonitor::GetEventLoop;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
EventLoop &GetEventLoop() { EventLoop &GetEventLoop() {
return loop; return loop;
} }
#endif #endif
public: public:
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
gcc_pure gcc_pure
uint64_t GetTime() const { uint64_t GetTime() const {
return g_source_get_time(&source->base); return g_source_get_time(&source->base);
...@@ -173,10 +181,12 @@ public: ...@@ -173,10 +181,12 @@ public:
#endif #endif
void InvalidateSockets() { void InvalidateSockets() {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
refresh = true; refresh = true;
IdleMonitor::Schedule(); IdleMonitor::Schedule();
#else #endif
#ifdef USE_GLIB_EVENTLOOP
/* no-op because GLib always calls the GSource's /* no-op because GLib always calls the GSource's
"prepare" method before each poll() anyway */ "prepare" method before each poll() anyway */
#endif #endif
...@@ -184,7 +194,7 @@ public: ...@@ -184,7 +194,7 @@ public:
void AddSocket(int fd, unsigned events) { void AddSocket(int fd, unsigned events) {
fds.emplace_front(*this, fd, events); fds.emplace_front(*this, fd, events);
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
g_source_add_poll(&source->base, &fds.front().pfd); g_source_add_poll(&source->base, &fds.front().pfd);
#endif #endif
} }
...@@ -201,9 +211,11 @@ public: ...@@ -201,9 +211,11 @@ public:
i->SetEvents(events); i->SetEvents(events);
prev = i; prev = i;
} else { } else {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
i->Steal(); i->Steal();
#else #endif
#ifdef USE_GLIB_EVENTLOOP
g_source_remove_poll(&source->base, &i->pfd); g_source_remove_poll(&source->base, &i->pfd);
#endif #endif
fds.erase_after(prev); fds.erase_after(prev);
...@@ -218,7 +230,7 @@ protected: ...@@ -218,7 +230,7 @@ protected:
virtual int PrepareSockets() = 0; virtual int PrepareSockets() = 0;
virtual void DispatchSockets() = 0; virtual void DispatchSockets() = 0;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
private: private:
void SetReady() { void SetReady() {
ready = true; ready = true;
...@@ -234,7 +246,9 @@ private: ...@@ -234,7 +246,9 @@ private:
virtual void OnIdle() final; virtual void OnIdle() final;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
public: public:
/* GSource callbacks */ /* GSource callbacks */
static gboolean Prepare(GSource *source, gint *timeout_r); static gboolean Prepare(GSource *source, gint *timeout_r);
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
void void
SocketMonitor::Dispatch(unsigned flags) SocketMonitor::Dispatch(unsigned flags)
...@@ -43,7 +43,9 @@ SocketMonitor::Dispatch(unsigned flags) ...@@ -43,7 +43,9 @@ SocketMonitor::Dispatch(unsigned flags)
Cancel(); Cancel();
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
/* /*
* GSource methods * GSource methods
...@@ -113,14 +115,14 @@ void ...@@ -113,14 +115,14 @@ void
SocketMonitor::Open(int _fd) SocketMonitor::Open(int _fd)
{ {
assert(fd < 0); assert(fd < 0);
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
assert(source == nullptr); assert(source == nullptr);
#endif #endif
assert(_fd >= 0); assert(_fd >= 0);
fd = _fd; fd = _fd;
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
poll = {fd, 0, 0}; poll = {fd, 0, 0};
source = (Source *)g_source_new(&socket_monitor_source_funcs, source = (Source *)g_source_new(&socket_monitor_source_funcs,
...@@ -142,7 +144,7 @@ SocketMonitor::Steal() ...@@ -142,7 +144,7 @@ SocketMonitor::Steal()
int result = fd; int result = fd;
fd = -1; fd = -1;
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
g_source_destroy(&source->base); g_source_destroy(&source->base);
g_source_unref(&source->base); g_source_unref(&source->base);
source = nullptr; source = nullptr;
...@@ -156,7 +158,7 @@ SocketMonitor::Abandon() ...@@ -156,7 +158,7 @@ SocketMonitor::Abandon()
{ {
assert(IsDefined()); assert(IsDefined());
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
fd = -1; fd = -1;
loop.Abandon(*this); loop.Abandon(*this);
#else #else
...@@ -178,7 +180,7 @@ SocketMonitor::Schedule(unsigned flags) ...@@ -178,7 +180,7 @@ SocketMonitor::Schedule(unsigned flags)
if (flags == GetScheduledFlags()) if (flags == GetScheduledFlags())
return; return;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
if (scheduled_flags == 0) if (scheduled_flags == 0)
loop.AddFD(fd, flags, *this); loop.AddFD(fd, flags, *this);
else if (flags == 0) else if (flags == 0)
...@@ -187,7 +189,9 @@ SocketMonitor::Schedule(unsigned flags) ...@@ -187,7 +189,9 @@ SocketMonitor::Schedule(unsigned flags)
loop.ModifyFD(fd, flags, *this); loop.ModifyFD(fd, flags, *this);
scheduled_flags = flags; scheduled_flags = flags;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
poll.events = flags; poll.events = flags;
poll.revents &= flags; poll.revents &= flags;
......
...@@ -22,9 +22,13 @@ ...@@ -22,9 +22,13 @@
#include "check.h" #include "check.h"
#ifdef USE_INTERNAL_EVENTLOOP
#ifdef USE_EPOLL #ifdef USE_EPOLL
#include <sys/epoll.h> #include <sys/epoll.h>
#else #endif
#endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h> #include <glib.h>
#endif #endif
...@@ -50,8 +54,7 @@ class EventLoop; ...@@ -50,8 +54,7 @@ class EventLoop;
* any of the subscribed events are ready. * any of the subscribed events are ready.
*/ */
class SocketMonitor { class SocketMonitor {
#ifdef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
#else
struct Source { struct Source {
GSource base; GSource base;
...@@ -62,38 +65,46 @@ class SocketMonitor { ...@@ -62,38 +65,46 @@ class SocketMonitor {
int fd; int fd;
EventLoop &loop; EventLoop &loop;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
/** /**
* A bit mask of events that is currently registered in the EventLoop. * A bit mask of events that is currently registered in the EventLoop.
*/ */
unsigned scheduled_flags; unsigned scheduled_flags;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
Source *source; Source *source;
GPollFD poll; GPollFD poll;
#endif #endif
public: public:
#ifdef USE_INTERNAL_EVENTLOOP
#ifdef USE_EPOLL #ifdef USE_EPOLL
static constexpr unsigned READ = EPOLLIN; static constexpr unsigned READ = EPOLLIN;
static constexpr unsigned WRITE = EPOLLOUT; static constexpr unsigned WRITE = EPOLLOUT;
static constexpr unsigned ERROR = EPOLLERR; static constexpr unsigned ERROR = EPOLLERR;
static constexpr unsigned HANGUP = EPOLLHUP; static constexpr unsigned HANGUP = EPOLLHUP;
#else #endif
#endif
#ifdef USE_GLIB_EVENTLOOP
static constexpr unsigned READ = G_IO_IN; static constexpr unsigned READ = G_IO_IN;
static constexpr unsigned WRITE = G_IO_OUT; static constexpr unsigned WRITE = G_IO_OUT;
static constexpr unsigned ERROR = G_IO_ERR; static constexpr unsigned ERROR = G_IO_ERR;
static constexpr unsigned HANGUP = G_IO_HUP; static constexpr unsigned HANGUP = G_IO_HUP;
#endif #endif
typedef std::make_signed<size_t>::type ssize_t; typedef std::make_signed<size_t>::type ssize_t;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
SocketMonitor(EventLoop &_loop) SocketMonitor(EventLoop &_loop)
:fd(-1), loop(_loop), scheduled_flags(0) {} :fd(-1), loop(_loop), scheduled_flags(0) {}
SocketMonitor(int _fd, EventLoop &_loop) SocketMonitor(int _fd, EventLoop &_loop)
:fd(_fd), loop(_loop), scheduled_flags(0) {} :fd(_fd), loop(_loop), scheduled_flags(0) {}
#else #endif
#ifdef USE_GLIB_EVENTLOOP
SocketMonitor(EventLoop &_loop) SocketMonitor(EventLoop &_loop)
:fd(-1), loop(_loop), source(nullptr) {} :fd(-1), loop(_loop), source(nullptr) {}
...@@ -134,9 +145,11 @@ public: ...@@ -134,9 +145,11 @@ public:
unsigned GetScheduledFlags() const { unsigned GetScheduledFlags() const {
assert(IsDefined()); assert(IsDefined());
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
return scheduled_flags; return scheduled_flags;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
return poll.events; return poll.events;
#endif #endif
} }
...@@ -173,9 +186,11 @@ protected: ...@@ -173,9 +186,11 @@ protected:
virtual bool OnSocketReady(unsigned flags) = 0; virtual bool OnSocketReady(unsigned flags) = 0;
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
void Dispatch(unsigned flags); void Dispatch(unsigned flags);
#else #endif
#ifdef USE_GLIB_EVENTLOOP
/* GSource callbacks */ /* GSource callbacks */
static gboolean Prepare(GSource *source, gint *timeout_r); static gboolean Prepare(GSource *source, gint *timeout_r);
static gboolean Check(GSource *source); static gboolean Check(GSource *source);
......
...@@ -25,10 +25,12 @@ void ...@@ -25,10 +25,12 @@ void
TimeoutMonitor::Cancel() TimeoutMonitor::Cancel()
{ {
if (IsActive()) { if (IsActive()) {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
active = false; active = false;
loop.CancelTimer(*this); loop.CancelTimer(*this);
#else #endif
#ifdef USE_GLIB_EVENTLOOP
g_source_destroy(source); g_source_destroy(source);
g_source_unref(source); g_source_unref(source);
source = nullptr; source = nullptr;
...@@ -41,10 +43,12 @@ TimeoutMonitor::Schedule(unsigned ms) ...@@ -41,10 +43,12 @@ TimeoutMonitor::Schedule(unsigned ms)
{ {
Cancel(); Cancel();
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
active = true; active = true;
loop.AddTimer(*this, ms); loop.AddTimer(*this, ms);
#else #endif
#ifdef USE_GLIB_EVENTLOOP
source = loop.AddTimeout(ms, Callback, this); source = loop.AddTimeout(ms, Callback, this);
#endif #endif
} }
...@@ -54,9 +58,11 @@ TimeoutMonitor::ScheduleSeconds(unsigned s) ...@@ -54,9 +58,11 @@ TimeoutMonitor::ScheduleSeconds(unsigned s)
{ {
Cancel(); Cancel();
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
Schedule(s * 1000u); Schedule(s * 1000u);
#else #endif
#ifdef USE_GLIB_EVENTLOOP
source = loop.AddTimeoutSeconds(s, Callback, this); source = loop.AddTimeoutSeconds(s, Callback, this);
#endif #endif
} }
...@@ -64,14 +70,14 @@ TimeoutMonitor::ScheduleSeconds(unsigned s) ...@@ -64,14 +70,14 @@ TimeoutMonitor::ScheduleSeconds(unsigned s)
void void
TimeoutMonitor::Run() TimeoutMonitor::Run()
{ {
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
Cancel(); Cancel();
#endif #endif
OnTimeout(); OnTimeout();
} }
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
gboolean gboolean
TimeoutMonitor::Callback(gpointer data) TimeoutMonitor::Callback(gpointer data)
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "check.h" #include "check.h"
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
#include <glib.h> #include <glib.h>
#endif #endif
...@@ -33,24 +33,28 @@ class EventLoop; ...@@ -33,24 +33,28 @@ class EventLoop;
* or Cancel() to cancel it. * or Cancel() to cancel it.
*/ */
class TimeoutMonitor { class TimeoutMonitor {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
friend class EventLoop; friend class EventLoop;
#endif #endif
EventLoop &loop; EventLoop &loop;
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
bool active; bool active;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
GSource *source; GSource *source;
#endif #endif
public: public:
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
TimeoutMonitor(EventLoop &_loop) TimeoutMonitor(EventLoop &_loop)
:loop(_loop), active(false) { :loop(_loop), active(false) {
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
TimeoutMonitor(EventLoop &_loop) TimeoutMonitor(EventLoop &_loop)
:loop(_loop), source(nullptr) {} :loop(_loop), source(nullptr) {}
#endif #endif
...@@ -64,9 +68,11 @@ public: ...@@ -64,9 +68,11 @@ public:
} }
bool IsActive() const { bool IsActive() const {
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
return active; return active;
#else #endif
#ifdef USE_GLIB_EVENTLOOP
return source != nullptr; return source != nullptr;
#endif #endif
} }
...@@ -81,7 +87,7 @@ protected: ...@@ -81,7 +87,7 @@ protected:
private: private:
void Run(); void Run();
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
static gboolean Callback(gpointer data); static gboolean Callback(gpointer data);
#endif #endif
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment