From 4a59018dcd766b1499d53e82ba938ce39013f7af Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 11 Mar 2021 09:02:02 +1100 Subject: [PATCH] Do not select on non-urgent fd when handling only urgent events This avoids 100% CPU usage when we have pending fifo input while running a shell process, as we will not end-up busy looping in pselect but not reading the available data due to being only processing urgent events. --- src/buffer_utils.cc | 2 +- src/event_manager.cc | 7 +++++-- src/event_manager.hh | 4 +++- src/json_ui.cc | 2 +- src/ncurses_ui.cc | 2 +- src/remote.cc | 8 ++++---- src/shell_manager.cc | 4 ++-- 7 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 206dc4b7..69cdb574 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -133,7 +133,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll struct FifoWatcher : FDWatcher { FifoWatcher(int fd, Buffer& buffer, bool scroll) - : FDWatcher(fd, FdEvents::Read, + : FDWatcher(fd, FdEvents::Read, EventMode::Normal, [](FDWatcher& watcher, FdEvents, EventMode mode) { if (mode == EventMode::Normal) static_cast(watcher).read_fifo(); diff --git a/src/event_manager.cc b/src/event_manager.cc index c4cf5e76..891780b2 100644 --- a/src/event_manager.cc +++ b/src/event_manager.cc @@ -12,8 +12,8 @@ namespace Kakoune { -FDWatcher::FDWatcher(int fd, FdEvents events, Callback callback) - : m_fd{fd}, m_events{events}, m_callback{std::move(callback)} +FDWatcher::FDWatcher(int fd, FdEvents events, EventMode mode, Callback callback) + : m_fd{fd}, m_events{events}, m_mode{mode}, m_callback{std::move(callback)} { EventManager::instance().m_fd_watchers.push_back(this); } @@ -80,6 +80,9 @@ bool EventManager::handle_next_events(EventMode mode, sigset_t* sigmask, bool bl FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); for (auto& watcher : m_fd_watchers) { + if (watcher->mode() == EventMode::Normal and mode == EventMode::Urgent) + continue; + const int fd = watcher->fd(); if (fd != -1) { diff --git a/src/event_manager.hh b/src/event_manager.hh index 7503e64a..b7a9720f 100644 --- a/src/event_manager.hh +++ b/src/event_manager.hh @@ -34,7 +34,7 @@ class FDWatcher { public: using Callback = std::function; - FDWatcher(int fd, FdEvents events, Callback callback); + FDWatcher(int fd, FdEvents events, EventMode mode, Callback callback); FDWatcher(const FDWatcher&) = delete; FDWatcher& operator=(const FDWatcher&) = delete; ~FDWatcher(); @@ -42,6 +42,7 @@ public: int fd() const { return m_fd; } FdEvents events() const { return m_events; } FdEvents& events() { return m_events; } + EventMode mode() const { return m_mode; } void run(FdEvents events, EventMode mode); @@ -51,6 +52,7 @@ public: private: int m_fd; FdEvents m_events; + EventMode m_mode; Callback m_callback; }; diff --git a/src/json_ui.cc b/src/json_ui.cc index 007c8ab0..111438c4 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -133,7 +133,7 @@ void rpc_call(StringView method, Args&&... args) } JsonUI::JsonUI() - : m_stdin_watcher{0, FdEvents::Read, + : m_stdin_watcher{0, FdEvents::Read, EventMode::Urgent, [this](FDWatcher&, FdEvents, EventMode mode) { parse_requests(mode); }}, m_dimensions{24, 80} diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index cbd38eba..17006c13 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -327,7 +327,7 @@ static void signal_handler(int) NCursesUI::NCursesUI() : m_cursor{CursorMode::Buffer, {}}, - m_stdin_watcher{STDIN_FILENO, FdEvents::Read, + m_stdin_watcher{STDIN_FILENO, FdEvents::Read, EventMode::Urgent, [this](FDWatcher&, FdEvents, EventMode) { if (not m_on_key) return; diff --git a/src/remote.cc b/src/remote.cc index 0cafd763..1b02251e 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -461,7 +461,7 @@ static bool send_data(int fd, RemoteBuffer& buffer, Optional ancillary_fd = } RemoteUI::RemoteUI(int socket, DisplayCoord dimensions) - : m_socket_watcher(socket, FdEvents::Read | FdEvents::Write, + : m_socket_watcher(socket, FdEvents::Read | FdEvents::Write, EventMode::Urgent, [this](FDWatcher& watcher, FdEvents events, EventMode) { const int sock = watcher.fd(); try @@ -663,7 +663,7 @@ RemoteClient::RemoteClient(StringView session, StringView name, std::unique_ptr< m_socket_watcher->events() |= FdEvents::Write; }); - m_socket_watcher.reset(new FDWatcher{sock, FdEvents::Read | FdEvents::Write, + m_socket_watcher.reset(new FDWatcher{sock, FdEvents::Read | FdEvents::Write, EventMode::Urgent, [this, reader = MsgReader{}](FDWatcher& watcher, FdEvents events, EventMode) mutable { const int sock = watcher.fd(); if (events & FdEvents::Write and send_data(sock, m_send_buffer)) @@ -777,7 +777,7 @@ class Server::Accepter { public: Accepter(int socket) - : m_socket_watcher(socket, FdEvents::Read, + : m_socket_watcher(socket, FdEvents::Read, EventMode::Urgent, [this](FDWatcher&, FdEvents, EventMode mode) { handle_available_input(mode); }) @@ -888,7 +888,7 @@ Server::Server(String session_name, bool is_daemon) m_accepters.emplace_back(new Accepter{sock}); }; - m_listener.reset(new FDWatcher{listen_sock, FdEvents::Read, accepter}); + m_listener.reset(new FDWatcher{listen_sock, FdEvents::Read, EventMode::Urgent, accepter}); } bool Server::rename_session(StringView name) diff --git a/src/shell_manager.cc b/src/shell_manager.cc index c39afadd..b683ac55 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -167,7 +167,7 @@ Vector generate_env(StringView cmdline, const Context& context, const Sh FDWatcher make_pipe_reader(Pipe& pipe, String& contents) { - return {pipe.read_fd(), FdEvents::Read, + return {pipe.read_fd(), FdEvents::Read, EventMode::Urgent, [&contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) { char buffer[1024]; while (fd_readable(pipe.read_fd())) @@ -188,7 +188,7 @@ FDWatcher make_pipe_writer(Pipe& pipe, StringView contents) { int flags = fcntl(pipe.write_fd(), F_GETFL, 0); fcntl(pipe.write_fd(), F_SETFL, flags | O_NONBLOCK); - return {pipe.write_fd(), FdEvents::Write, + return {pipe.write_fd(), FdEvents::Write, EventMode::Urgent, [contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) mutable { while (fd_writable(pipe.write_fd())) {