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:
		
							
								
								
									
										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
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user