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)
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'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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