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.
This commit is contained in:
Denis Krjuchkov 2013-11-27 17:04:38 +06:00
parent 22fb49fa90
commit 46bab7e4b9
15 changed files with 295 additions and 114 deletions

View File

@ -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])])
@ -156,6 +155,63 @@ AC_SEARCH_LIBS([exp], [m],,
AC_CHECK_HEADERS(locale.h) AC_CHECK_HEADERS(locale.h)
AC_CHECK_HEADERS(valgrind/memcheck.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 ---------------------------------------------------------------------------
dnl Allow tools to be specifically built dnl Allow tools to be specifically built
dnl --------------------------------------------------------------------------- dnl ---------------------------------------------------------------------------
@ -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'

View File

@ -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],)])
])

View File

@ -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
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:
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() {

View File

@ -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()
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()
#endif #endif
} }
#ifdef USE_EPOLL #ifdef USE_INTERNAL_EVENTLOOP
bool bool
DeferredMonitor::OnSocketReady(unsigned) 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()

View File

@ -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;
* 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:
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

View File

@ -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()
/* 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()
{ {
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()
OnIdle(); OnIdle();
} }
#ifndef USE_EPOLL #ifdef USE_GLIB_EVENTLOOP
gboolean gboolean
IdleMonitor::Callback(gpointer data) IdleMonitor::Callback(gpointer data)

View File

@ -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;
* 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:
} }
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:
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
}; };

View File

@ -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)
: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()
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()
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()
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()
} }
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)
return true; return true;
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
guint guint
EventLoop::AddIdle(GSourceFunc function, gpointer data) EventLoop::AddIdle(GSourceFunc function, gpointer data)

View File

@ -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 @@
#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;
* @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
} }
}; };
EPollFD epoll;
WakeFD wake_fd; WakeFD wake_fd;
std::multiset<TimerRecord> timers; std::multiset<TimerRecord> timers;
@ -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
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:
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:
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)),

View File

@ -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()
} }
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
/** /**
* The vtable for our GSource implementation. Unfortunately, we * The vtable for our GSource implementation. Unfortunately, we

View File

@ -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;
* 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
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
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:
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:
#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:
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:
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:
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:
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);

View File

@ -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)
Cancel(); Cancel();
} }
#else #endif
#ifdef USE_GLIB_EVENTLOOP
/* /*
* GSource methods * GSource methods
@ -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()
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()
{ {
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)
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)
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;

View File

@ -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;
* 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 {
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:
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:
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);

View File

@ -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)
{ {
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)
{ {
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)
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)

View File

@ -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;
* 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:
} }
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:
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
}; };