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:
parent
22fb49fa90
commit
46bab7e4b9
68
configure.ac
68
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'
|
||||
|
|
|
@ -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],)])
|
||||
])
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <assert.h>
|
||||
|
||||
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<void()> &&_f)
|
||||
:f(std::move(_f)), done(false) {
|
||||
loop.AddCall([this](){
|
||||
this->DoRun();
|
||||
});
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLIB_EVENTLOOP
|
||||
BlockingCallMonitor(EventLoop &_loop, std::function<void()> &&_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() {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 <glib.h>
|
||||
#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<guint> 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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "check.h"
|
||||
|
||||
#ifndef USE_EPOLL
|
||||
#ifdef USE_GLIB_EVENTLOOP
|
||||
#include <glib.h>
|
||||
#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
|
||||
};
|
||||
|
|
|
@ -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<void()> &&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)
|
||||
|
|
|
@ -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 <functional>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLIB_EVENTLOOP
|
||||
#include <glib.h>
|
||||
#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<TimerRecord> 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)),
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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 <glib.h>
|
||||
#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<SingleFD> 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);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <sys/socket.h>
|
||||
#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;
|
||||
|
||||
|
|
|
@ -22,9 +22,13 @@
|
|||
|
||||
#include "check.h"
|
||||
|
||||
#ifdef USE_INTERNAL_EVENTLOOP
|
||||
#ifdef USE_EPOLL
|
||||
#include <sys/epoll.h>
|
||||
#else
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLIB_EVENTLOOP
|
||||
#include <glib.h>
|
||||
#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,23 +65,29 @@ 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;
|
||||
|
@ -87,13 +96,15 @@ public:
|
|||
|
||||
typedef std::make_signed<size_t>::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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "check.h"
|
||||
|
||||
#ifndef USE_EPOLL
|
||||
#ifdef USE_GLIB_EVENTLOOP
|
||||
#include <glib.h>
|
||||
#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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue