From bb288f02848793a85b74262063d1bd9c7bc7dd78 Mon Sep 17 00:00:00 2001 From: Denis Krjuchkov Date: Thu, 28 Nov 2013 16:37:23 +0600 Subject: event: introduce generic API for internal event loop --- src/event/Loop.cxx | 41 +++++++------------- src/event/Loop.hxx | 24 +++--------- src/event/PollGroup.hxx | 29 ++++++++++++++ src/event/PollGroupEPoll.hxx | 91 ++++++++++++++++++++++++++++++++++++++++++++ src/event/SocketMonitor.cxx | 3 +- src/event/SocketMonitor.hxx | 14 +++---- 6 files changed, 147 insertions(+), 55 deletions(-) create mode 100644 src/event/PollGroup.hxx create mode 100644 src/event/PollGroupEPoll.hxx (limited to 'src/event') diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index ccba7bb45..f7b3df022 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -33,9 +33,6 @@ 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()); @@ -60,23 +57,18 @@ EventLoop::Break() AddCall([this]() { Break(); }); } -void -EventLoop::Abandon(SocketMonitor &m) +bool +EventLoop::Abandon(int _fd, 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 + poll_result.Clear(&m); + return poll_group.Abandon(_fd); } bool EventLoop::RemoveFD(int _fd, SocketMonitor &m) { -#ifdef USE_EPOLL - Abandon(m); - return epoll.Remove(_fd); -#endif + poll_result.Clear(&m); + return poll_group.Remove(_fd); } void @@ -168,34 +160,29 @@ EventLoop::Run() timeout */ continue; -#ifdef USE_EPOLL /* wait for new event */ - const int n = epoll.Wait(events, MAX_EVENTS, timeout_ms); - n_events = std::max(n, 0); + poll_group.ReadEvents(poll_result, timeout_ms); now_ms = ::MonotonicClockMS(); assert(!quit); /* invoke sockets */ - - for (int i = 0; i < n; ++i) { - const auto &e = events[i]; - - if (e.events != 0) { - SocketMonitor &m = *(SocketMonitor *)e.data.ptr; - m.Dispatch(e.events); + for (int i = 0; i < poll_result.GetSize(); ++i) { + auto events = poll_result.GetEvents(i); + if (events != 0) { + auto m = (SocketMonitor *)poll_result.GetObject(i); + m->Dispatch(events); if (quit) break; } } - n_events = 0; -#endif - } while (!quit); + poll_result.Reset(); + } while (!quit); #endif #ifdef USE_GLIB_EVENTLOOP diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index f188c7cc0..029d01245 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -25,10 +25,7 @@ #include "Compiler.h" #ifdef USE_INTERNAL_EVENTLOOP -#ifdef USE_EPOLL -#include "system/EPollFD.hxx" -#endif - +#include "PollGroup.hxx" #include "thread/Mutex.hxx" #include "WakeFD.hxx" #include "SocketMonitor.hxx" @@ -99,13 +96,8 @@ class EventLoop final bool quit; -#ifdef USE_EPOLL - EPollFD epoll; - static constexpr unsigned MAX_EVENTS = 16; - unsigned n_events; - epoll_event events[MAX_EVENTS]; -#endif - + PollGroup poll_group; + PollResult poll_result; #endif #ifdef USE_GLIB_EVENTLOOP @@ -140,15 +132,11 @@ public: void Break(); bool AddFD(int _fd, unsigned flags, SocketMonitor &m) { -#ifdef USE_EPOLL - return epoll.Add(_fd, flags, &m); -#endif + return poll_group.Add(_fd, flags, &m); } bool ModifyFD(int _fd, unsigned flags, SocketMonitor &m) { -#ifdef USE_EPOLL - return epoll.Modify(_fd, flags, &m); -#endif + return poll_group.Modify(_fd, flags, &m); } /** @@ -156,7 +144,7 @@ public: * has been closed. This is like RemoveFD(), but does not * attempt to use #EPOLL_CTL_DEL. */ - void Abandon(SocketMonitor &m); + bool Abandon(int fd, SocketMonitor &m); bool RemoveFD(int fd, SocketMonitor &m); diff --git a/src/event/PollGroup.hxx b/src/event/PollGroup.hxx new file mode 100644 index 000000000..824a6ecfe --- /dev/null +++ b/src/event/PollGroup.hxx @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_EVENT_POLLGROUP_HXX +#define MPD_EVENT_POLLGROUP_HXX + +#ifdef USE_EPOLL +#include "PollGroupEPoll.hxx" +typedef PollResultEPoll PollResult; +typedef PollGroupEPoll PollGroup; +#endif + +#endif diff --git a/src/event/PollGroupEPoll.hxx b/src/event/PollGroupEPoll.hxx new file mode 100644 index 000000000..5d50cef93 --- /dev/null +++ b/src/event/PollGroupEPoll.hxx @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_EVENT_POLLGROUP_EPOLL_HXX +#define MPD_EVENT_POLLGROUP_EPOLL_HXX + +#include "check.h" + +#include "Compiler.h" +#include "system/EPollFD.hxx" + +#include +#include + +class PollResultEPoll +{ + friend class PollGroupEPoll; + + std::array events; + int n_events; +public: + PollResultEPoll() : n_events(0) { } + + int GetSize() const { return n_events; } + unsigned GetEvents(int i) { return events[i].events; } + void *GetObject(int i) { return events[i].data.ptr; } + void Reset() { n_events = 0; } + + void Clear(void *obj) { + for (int i = 0; i < n_events; ++i) + if (events[i].data.ptr == obj) + events[i].events = 0; + } +}; + +class PollGroupEPoll +{ + EPollFD epoll; + + PollGroupEPoll(PollGroupEPoll &) = delete; + PollGroupEPoll &operator=(PollGroupEPoll &) = delete; +public: + static constexpr unsigned READ = EPOLLIN; + static constexpr unsigned WRITE = EPOLLOUT; + static constexpr unsigned ERROR = EPOLLERR; + static constexpr unsigned HANGUP = EPOLLHUP; + + PollGroupEPoll() = default; + + void ReadEvents(PollResultEPoll &result, int timeout_ms) { + int ret = epoll.Wait(result.events.data(), result.events.size(), + timeout_ms); + result.n_events = std::max(0, ret); + } + + bool Add(int fd, unsigned events, void *obj) { + return epoll.Add(fd, events, obj); + } + + bool Modify(int fd, unsigned events, void *obj) { + return epoll.Modify(fd, events, obj); + } + + bool Remove(int fd) { + return epoll.Remove(fd); + } + + bool Abandon(gcc_unused int fd) { + // Nothing to do in this implementation. + // Closed descriptors are automatically unregistered. + return true; + } +}; + +#endif diff --git a/src/event/SocketMonitor.cxx b/src/event/SocketMonitor.cxx index e88427d53..769efba82 100644 --- a/src/event/SocketMonitor.cxx +++ b/src/event/SocketMonitor.cxx @@ -158,8 +158,9 @@ SocketMonitor::Abandon() assert(IsDefined()); #ifdef USE_INTERNAL_EVENTLOOP + int old_fd = fd; fd = -1; - loop.Abandon(*this); + loop.Abandon(old_fd, *this); #else Steal(); #endif diff --git a/src/event/SocketMonitor.hxx b/src/event/SocketMonitor.hxx index 4d3e5aea2..f6aac2bd6 100644 --- a/src/event/SocketMonitor.hxx +++ b/src/event/SocketMonitor.hxx @@ -23,9 +23,7 @@ #include "check.h" #ifdef USE_INTERNAL_EVENTLOOP -#ifdef USE_EPOLL -#include -#endif +#include "PollGroup.hxx" #endif #ifdef USE_GLIB_EVENTLOOP @@ -79,12 +77,10 @@ class SocketMonitor { 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; -#endif + static constexpr unsigned READ = PollGroup::READ; + static constexpr unsigned WRITE = PollGroup::WRITE; + static constexpr unsigned ERROR = PollGroup::ERROR; + static constexpr unsigned HANGUP = PollGroup::HANGUP; #endif #ifdef USE_GLIB_EVENTLOOP -- cgit v1.2.3