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])
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])])
......@@ -157,6 +156,63 @@ 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
};
......
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