From cdf8ac001cd885dca68d3d4fb13fb5c65335930b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 5 May 2020 15:18:02 +0200 Subject: [PATCH] event/Loop: integrate io_uring support --- src/event/Loop.cxx | 34 ++++++++++++++++++++++++++ src/event/Loop.hxx | 19 +++++++++++++++ src/event/UringManager.cxx | 47 +++++++++++++++++++++++++++++++++++ src/event/UringManager.hxx | 50 ++++++++++++++++++++++++++++++++++++++ src/event/meson.build | 9 +++++++ 5 files changed, 159 insertions(+) create mode 100644 src/event/UringManager.cxx create mode 100644 src/event/UringManager.hxx diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index d2fed9c4f..7a7c77dcc 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -23,6 +23,12 @@ #include "DeferEvent.hxx" #include "util/ScopeExit.hxx" +#ifdef HAVE_URING +#include "UringManager.hxx" +#include "util/PrintException.hxx" +#include +#endif + EventLoop::EventLoop(ThreadId _thread) :SocketMonitor(*this), /* if this instance is hosted by an EventThread (no ThreadId @@ -43,6 +49,25 @@ EventLoop::~EventLoop() noexcept assert(timers.empty()); } +#ifdef HAVE_URING + +Uring::Queue * +EventLoop::GetUring() noexcept +{ + if (!uring_initialized) { + try { + uring = std::make_unique(*this); + } catch (...) { + fprintf(stderr, "Failed to initialize io_uring: "); + PrintException(std::current_exception()); + } + } + + return uring.get(); +} + +#endif + void EventLoop::Break() noexcept { @@ -155,6 +180,15 @@ EventLoop::Run() noexcept SocketMonitor::Schedule(SocketMonitor::READ); AtScopeExit(this) { +#ifdef HAVE_URING + /* make sure that the Uring::Manager gets destructed + from within the EventThread, or else its + destruction in another thread will cause assertion + failures */ + uring.reset(); + uring_initialized = false; +#endif + SocketMonitor::Cancel(); }; diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx index d16f91c57..53af91ff5 100644 --- a/src/event/Loop.hxx +++ b/src/event/Loop.hxx @@ -38,6 +38,12 @@ #include #include +#include "io/uring/Features.h" +#ifdef HAVE_URING +#include +namespace Uring { class Queue; class Manager; } +#endif + /** * An event loop that polls for events on file/socket descriptors. * @@ -82,6 +88,10 @@ class EventLoop final : SocketMonitor boost::intrusive::constant_time_size> DeferredList; DeferredList deferred; +#ifdef HAVE_URING + std::unique_ptr uring; +#endif + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); /** @@ -108,6 +118,10 @@ class EventLoop final : SocketMonitor */ bool busy = true; +#ifdef HAVE_URING + bool uring_initialized = false; +#endif + PollGroup poll_group; PollResult poll_result; @@ -135,6 +149,11 @@ public: return now; } +#ifdef HAVE_URING + gcc_pure + Uring::Queue *GetUring() noexcept; +#endif + /** * Stop execution of this #EventLoop at the next chance. This * method is thread-safe and non-blocking: after returning, it diff --git a/src/event/UringManager.cxx b/src/event/UringManager.cxx new file mode 100644 index 000000000..9bb9ab48d --- /dev/null +++ b/src/event/UringManager.cxx @@ -0,0 +1,47 @@ +/* + * Copyright 2003-2020 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. + */ + +#include "UringManager.hxx" +#include "util/PrintException.hxx" + +namespace Uring { + +bool +Manager::OnSocketReady(unsigned) noexcept +{ + try { + DispatchCompletions(); + return true; + } catch (...) { + PrintException(std::current_exception()); + return false; + } +} + +void +Manager::OnIdle() noexcept +{ + try { + Submit(); + } catch (...) { + PrintException(std::current_exception()); + } +} + +} // namespace Uring diff --git a/src/event/UringManager.hxx b/src/event/UringManager.hxx new file mode 100644 index 000000000..d52f055d9 --- /dev/null +++ b/src/event/UringManager.hxx @@ -0,0 +1,50 @@ +/* + * Copyright 2003-2020 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. + */ + +#pragma once + +#include "SocketMonitor.hxx" +#include "IdleMonitor.hxx" +#include "io/uring/Queue.hxx" + +namespace Uring { + +class Manager final : public Queue, SocketMonitor, IdleMonitor { +public: + explicit Manager(EventLoop &event_loop) + :Queue(1024, 0), + SocketMonitor(SocketDescriptor::FromFileDescriptor(GetFileDescriptor()), + event_loop), + IdleMonitor(event_loop) + { + SocketMonitor::ScheduleRead(); + } + + void Push(struct io_uring_sqe &sqe, + Operation &operation) noexcept override { + AddPending(sqe, operation); + IdleMonitor::Schedule(); + } + +private: + bool OnSocketReady(unsigned flags) noexcept override; + void OnIdle() noexcept override; +}; + +} // namespace Uring diff --git a/src/event/meson.build b/src/event/meson.build index 6877bc37a..e4de136b0 100644 --- a/src/event/meson.build +++ b/src/event/meson.build @@ -1,3 +1,9 @@ +event_sources = [] + +if uring_dep.found() + event_sources += 'UringManager.cxx' +endif + event = static_library( 'event', 'PollGroupPoll.cxx', @@ -15,10 +21,12 @@ event = static_library( 'Call.cxx', 'Thread.cxx', 'Loop.cxx', + event_sources, include_directories: inc, dependencies: [ boost_dep, log_dep, + uring_dep, ], ) @@ -29,5 +37,6 @@ event_dep = declare_dependency( net_dep, system_dep, boost_dep, + uring_dep, ], )