diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 735657e0..4ff1c1cf 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -114,7 +114,8 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll) ValueId fifo_watcher_id = s_fifo_watcher_id; std::unique_ptr watcher( - new FDWatcher(fd, [buffer, scroll, fifo_watcher_id](FDWatcher& watcher, EventMode mode) { + new FDWatcher(fd, FdEvents::Read, + [buffer, scroll, fifo_watcher_id](FDWatcher& watcher, FdEvents, EventMode mode) { if (mode != EventMode::Normal) return; diff --git a/src/event_manager.cc b/src/event_manager.cc index d42f53c8..221a6d0d 100644 --- a/src/event_manager.cc +++ b/src/event_manager.cc @@ -7,8 +7,8 @@ namespace Kakoune { -FDWatcher::FDWatcher(int fd, Callback callback) - : m_fd{fd}, m_callback{std::move(callback)} +FDWatcher::FDWatcher(int fd, FdEvents events, Callback callback) + : m_fd{fd}, m_events{events}, m_callback{std::move(callback)} { EventManager::instance().m_fd_watchers.push_back(this); } @@ -18,9 +18,9 @@ FDWatcher::~FDWatcher() unordered_erase(EventManager::instance().m_fd_watchers, this); } -void FDWatcher::run(EventMode mode) +void FDWatcher::run(FdEvents events, EventMode mode) { - m_callback(*this, mode); + m_callback(*this, events, mode); } void FDWatcher::close_fd() @@ -71,15 +71,21 @@ EventManager::~EventManager() void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) { int max_fd = 0; - fd_set rfds; - FD_ZERO(&rfds); + fd_set rfds, wfds, efds; + FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); for (auto& watcher : m_fd_watchers) { const int fd = watcher->fd(); if (fd != -1) { max_fd = std::max(fd, max_fd); - FD_SET(fd, &rfds); + auto events = watcher->events(); + if (events & FdEvents::Read) + FD_SET(fd, &rfds); + if (events & FdEvents::Write) + FD_SET(fd, &wfds); + if (events & FdEvents::Except) + FD_SET(fd, &efds); } } @@ -101,7 +107,7 @@ void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) ts = timespec{ (time_t)secs.count(), (long)(nsecs - secs).count() }; } } - int res = pselect(max_fd + 1, &rfds, nullptr, nullptr, + int res = pselect(max_fd + 1, &rfds, &wfds, &efds, with_timeout ? &ts : nullptr, sigmask); // copy forced fds *after* select, so that signal handlers can write to @@ -111,12 +117,18 @@ void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) for (int fd = 0; fd < max_fd + 1; ++fd) { - if ((res > 0 and FD_ISSET(fd, &rfds)) or FD_ISSET(fd, &forced)) + auto events = FD_ISSET(fd, &forced) ? FdEvents::Read : FdEvents::None; + if (res > 0) + events |= (FD_ISSET(fd, &rfds) ? FdEvents::Read : FdEvents::None) | + (FD_ISSET(fd, &wfds) ? FdEvents::Write : FdEvents::None) | + (FD_ISSET(fd, &efds) ? FdEvents::Except : FdEvents::None); + + if (events != FdEvents::None) { auto it = find_if(m_fd_watchers, [fd](const FDWatcher* w){return w->fd() == fd; }); if (it != m_fd_watchers.end()) - (*it)->run(mode); + (*it)->run(events, mode); } } diff --git a/src/event_manager.hh b/src/event_manager.hh index 5121b324..3d222f48 100644 --- a/src/event_manager.hh +++ b/src/event_manager.hh @@ -20,24 +20,38 @@ enum class EventMode Urgent, }; +enum class FdEvents +{ + None = 0, + Read = 1 << 0, + Write = 1 << 1, + Except = 1 << 2, +}; + +template<> struct WithBitOps : std::true_type {}; + class FDWatcher { public: - using Callback = std::function; - FDWatcher(int fd, Callback callback); + using Callback = std::function; + FDWatcher(int fd, FdEvents events, Callback callback); FDWatcher(const FDWatcher&) = delete; FDWatcher& operator=(const FDWatcher&) = delete; ~FDWatcher(); int fd() const { return m_fd; } - void run(EventMode mode); + FdEvents events() const { return m_events; } + FdEvents& events() { return m_events; } + + void run(FdEvents events, EventMode mode); void close_fd(); void disable() { m_fd = -1; } private: - int m_fd; - Callback m_callback; + int m_fd; + FdEvents m_events; + Callback m_callback; }; class Timer diff --git a/src/json_ui.cc b/src/json_ui.cc index 0a82e07e..95697d73 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -164,7 +164,8 @@ void rpc_call(StringView method, Args&&... args) } JsonUI::JsonUI() - : m_stdin_watcher{0, [this](FDWatcher&, EventMode mode) { + : m_stdin_watcher{0, FdEvents::Read, + [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 89aefcc0..64f9a82a 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -219,7 +219,8 @@ void on_term_resize(int) } NCursesUI::NCursesUI() - : m_stdin_watcher{0, [this](FDWatcher&, EventMode mode) { + : m_stdin_watcher{0, FdEvents::Read, + [this](FDWatcher&, FdEvents, EventMode mode) { if (not m_on_key) return; diff --git a/src/remote.cc b/src/remote.cc index 682971ef..7d44c2e5 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -345,7 +345,8 @@ private: RemoteUI::RemoteUI(int socket, DisplayCoord dimensions) - : m_socket_watcher(socket, [this](FDWatcher& watcher, EventMode mode) { + : m_socket_watcher(socket, FdEvents::Read, + [this](FDWatcher& watcher, FdEvents, EventMode mode) { const int sock = watcher.fd(); try { @@ -506,7 +507,8 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr&& }); MsgReader reader; - m_socket_watcher.reset(new FDWatcher{sock, [this, reader](FDWatcher& watcher, EventMode) mutable { + m_socket_watcher.reset(new FDWatcher{sock, FdEvents::Read, + [this, reader](FDWatcher& watcher, FdEvents, EventMode) mutable { const int sock = watcher.fd(); while (fd_readable(sock) and not reader.ready()) reader.read_available(sock); @@ -593,8 +595,8 @@ class Server::Accepter { public: Accepter(int socket) - : m_socket_watcher(socket, - [this](FDWatcher&, EventMode mode) { + : m_socket_watcher(socket, FdEvents::Read, + [this](FDWatcher&, FdEvents, EventMode mode) { if (mode == EventMode::Normal) handle_available_input(); }) @@ -681,7 +683,7 @@ Server::Server(String session_name) if (listen(listen_sock, 4) == -1) throw runtime_error(format("unable to listen on socket '{}'", addr.sun_path)); - auto accepter = [this](FDWatcher& watcher, EventMode mode) { + auto accepter = [this](FDWatcher& watcher, FdEvents, EventMode mode) { sockaddr_un client_addr; socklen_t client_addr_len = sizeof(sockaddr_un); int sock = accept(watcher.fd(), (sockaddr*) &client_addr, @@ -692,7 +694,7 @@ Server::Server(String session_name) m_accepters.emplace_back(new Accepter{sock}); }; - m_listener.reset(new FDWatcher{listen_sock, accepter}); + m_listener.reset(new FDWatcher{listen_sock, FdEvents::Read, accepter}); } bool Server::rename_session(StringView name) diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 81df87ee..25cc2be6 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -158,8 +158,8 @@ std::pair ShellManager::eval( struct PipeReader : FDWatcher { PipeReader(Pipe& pipe, String& contents) - : FDWatcher(pipe.read_fd(), - [&contents, &pipe](FDWatcher& watcher, EventMode) { + : FDWatcher(pipe.read_fd(), FdEvents::Read, + [&contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) { char buffer[1024]; size_t size = ::read(pipe.read_fd(), buffer, 1024); if (size <= 0)