diff options
author | Max Kellermann <max@duempel.org> | 2013-08-07 22:16:59 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-08-10 13:54:23 +0200 |
commit | c1f4f1fdb64d97b5c3461723a8482ca64efea30e (patch) | |
tree | 54c8a9c1466beec0dbfac1c0b5f5773060c1aa2b /src/event/Loop.hxx | |
parent | 342333f72a484e9f394026666c4b20e54dc9b756 (diff) |
EventLoop: new implementation using epoll
Implement an event loop without GLib.
Diffstat (limited to 'src/event/Loop.hxx')
-rw-r--r-- | src/event/Loop.hxx | 123 |
1 files changed, 112 insertions, 11 deletions
diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index e26da9687..ec90cdacf 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -24,13 +24,76 @@ #include "thread/Id.hxx" #include "gcc.h" +#ifdef USE_EPOLL +#include "system/EPollFD.hxx" +#include "thread/Mutex.hxx" +#include "WakeFD.hxx" +#include "SocketMonitor.hxx" + +#include <functional> +#include <list> +#include <set> +#else #include <glib.h> +#endif + +#ifdef USE_EPOLL +class TimeoutMonitor; +class IdleMonitor; +class SocketMonitor; +#endif #include <assert.h> -class EventLoop { +class EventLoop final +#ifdef USE_EPOLL + : private SocketMonitor +#endif +{ +#ifdef USE_EPOLL + struct TimerRecord { + /** + * Projected monotonic_clock_ms() value when this + * timer is due. + */ + const unsigned due_ms; + + TimeoutMonitor &timer; + + constexpr TimerRecord(TimeoutMonitor &_timer, + unsigned _due_ms) + :due_ms(_due_ms), timer(_timer) {} + + bool operator<(const TimerRecord &other) const { + return due_ms < other.due_ms; + } + + bool IsDue(unsigned _now_ms) const { + return _now_ms >= due_ms; + } + }; + + EPollFD epoll; + + WakeFD wake_fd; + + std::multiset<TimerRecord> timers; + std::list<IdleMonitor *> idle; + + Mutex mutex; + std::list<std::function<void()>> calls; + + unsigned now_ms; + + bool quit; + + static constexpr unsigned MAX_EVENTS = 16; + unsigned n_events; + epoll_event events[MAX_EVENTS]; +#else GMainContext *context; GMainLoop *loop; +#endif /** * A reference to the thread that is currently inside Run(). @@ -38,6 +101,43 @@ class EventLoop { ThreadId thread; public: +#ifdef USE_EPOLL + struct Default {}; + + EventLoop(Default dummy=Default()); + ~EventLoop(); + + unsigned GetTimeMS() const { + return now_ms; + } + + void Break(); + + bool AddFD(int _fd, unsigned flags, SocketMonitor &m) { + return epoll.Add(_fd, flags, &m); + } + + bool ModifyFD(int _fd, unsigned flags, SocketMonitor &m) { + return epoll.Modify(_fd, flags, &m); + } + + bool RemoveFD(int fd, SocketMonitor &m); + + void AddIdle(IdleMonitor &i); + void RemoveIdle(IdleMonitor &i); + + void AddTimer(TimeoutMonitor &t, unsigned ms); + void CancelTimer(TimeoutMonitor &t); + + void AddCall(std::function<void()> &&f); + + void Run(); + +private: + virtual bool OnSocketReady(unsigned flags) override; + +public: +#else EventLoop() :context(g_main_context_new()), loop(g_main_loop_new(context, false)), @@ -54,16 +154,6 @@ public: g_main_context_unref(context); } - /** - * Are we currently running inside this EventLoop's thread? - */ - gcc_pure - bool IsInside() const { - assert(!thread.IsNull()); - - return thread.IsInside(); - } - GMainContext *GetContext() { return context; } @@ -85,6 +175,17 @@ public: GSource *AddTimeoutSeconds(guint interval_s, GSourceFunc function, gpointer data); +#endif + + /** + * Are we currently running inside this EventLoop's thread? + */ + gcc_pure + bool IsInside() const { + assert(!thread.IsNull()); + + return thread.IsInside(); + } }; #endif /* MAIN_NOTIFY_H */ |