Make FDWatcher support Read, Write and Except events, instead of just Read

This commit is contained in:
Maxime Coste 2016-11-30 13:59:08 +00:00 committed by Maxime Coste
parent 99a3388e41
commit 7defdd3039
7 changed files with 57 additions and 26 deletions

View File

@ -114,7 +114,8 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll)
ValueId fifo_watcher_id = s_fifo_watcher_id; ValueId fifo_watcher_id = s_fifo_watcher_id;
std::unique_ptr<FDWatcher, decltype(watcher_deleter)> watcher( std::unique_ptr<FDWatcher, decltype(watcher_deleter)> 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) if (mode != EventMode::Normal)
return; return;

View File

@ -7,8 +7,8 @@
namespace Kakoune namespace Kakoune
{ {
FDWatcher::FDWatcher(int fd, Callback callback) FDWatcher::FDWatcher(int fd, FdEvents events, Callback callback)
: m_fd{fd}, m_callback{std::move(callback)} : m_fd{fd}, m_events{events}, m_callback{std::move(callback)}
{ {
EventManager::instance().m_fd_watchers.push_back(this); EventManager::instance().m_fd_watchers.push_back(this);
} }
@ -18,9 +18,9 @@ FDWatcher::~FDWatcher()
unordered_erase(EventManager::instance().m_fd_watchers, this); 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() void FDWatcher::close_fd()
@ -71,15 +71,21 @@ EventManager::~EventManager()
void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask)
{ {
int max_fd = 0; int max_fd = 0;
fd_set rfds; fd_set rfds, wfds, efds;
FD_ZERO(&rfds); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
for (auto& watcher : m_fd_watchers) for (auto& watcher : m_fd_watchers)
{ {
const int fd = watcher->fd(); const int fd = watcher->fd();
if (fd != -1) if (fd != -1)
{ {
max_fd = std::max(fd, max_fd); max_fd = std::max(fd, max_fd);
auto events = watcher->events();
if (events & FdEvents::Read)
FD_SET(fd, &rfds); 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() }; 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); with_timeout ? &ts : nullptr, sigmask);
// copy forced fds *after* select, so that signal handlers can write to // 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) 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, auto it = find_if(m_fd_watchers,
[fd](const FDWatcher* w){return w->fd() == fd; }); [fd](const FDWatcher* w){return w->fd() == fd; });
if (it != m_fd_watchers.end()) if (it != m_fd_watchers.end())
(*it)->run(mode); (*it)->run(events, mode);
} }
} }

View File

@ -20,23 +20,37 @@ enum class EventMode
Urgent, Urgent,
}; };
enum class FdEvents
{
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Except = 1 << 2,
};
template<> struct WithBitOps<FdEvents> : std::true_type {};
class FDWatcher class FDWatcher
{ {
public: public:
using Callback = std::function<void (FDWatcher& watcher, EventMode mode)>; using Callback = std::function<void (FDWatcher& watcher, FdEvents events, EventMode mode)>;
FDWatcher(int fd, Callback callback); FDWatcher(int fd, FdEvents events, Callback callback);
FDWatcher(const FDWatcher&) = delete; FDWatcher(const FDWatcher&) = delete;
FDWatcher& operator=(const FDWatcher&) = delete; FDWatcher& operator=(const FDWatcher&) = delete;
~FDWatcher(); ~FDWatcher();
int fd() const { return m_fd; } 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 close_fd();
void disable() { m_fd = -1; } void disable() { m_fd = -1; }
private: private:
int m_fd; int m_fd;
FdEvents m_events;
Callback m_callback; Callback m_callback;
}; };

View File

@ -164,7 +164,8 @@ void rpc_call(StringView method, Args&&... args)
} }
JsonUI::JsonUI() JsonUI::JsonUI()
: m_stdin_watcher{0, [this](FDWatcher&, EventMode mode) { : m_stdin_watcher{0, FdEvents::Read,
[this](FDWatcher&, FdEvents, EventMode mode) {
parse_requests(mode); parse_requests(mode);
}}, m_dimensions{24, 80} }}, m_dimensions{24, 80}
{ {

View File

@ -219,7 +219,8 @@ void on_term_resize(int)
} }
NCursesUI::NCursesUI() 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) if (not m_on_key)
return; return;

View File

@ -345,7 +345,8 @@ private:
RemoteUI::RemoteUI(int socket, DisplayCoord dimensions) 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(); const int sock = watcher.fd();
try try
{ {
@ -506,7 +507,8 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
}); });
MsgReader reader; 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(); const int sock = watcher.fd();
while (fd_readable(sock) and not reader.ready()) while (fd_readable(sock) and not reader.ready())
reader.read_available(sock); reader.read_available(sock);
@ -593,8 +595,8 @@ class Server::Accepter
{ {
public: public:
Accepter(int socket) Accepter(int socket)
: m_socket_watcher(socket, : m_socket_watcher(socket, FdEvents::Read,
[this](FDWatcher&, EventMode mode) { [this](FDWatcher&, FdEvents, EventMode mode) {
if (mode == EventMode::Normal) if (mode == EventMode::Normal)
handle_available_input(); handle_available_input();
}) })
@ -681,7 +683,7 @@ Server::Server(String session_name)
if (listen(listen_sock, 4) == -1) if (listen(listen_sock, 4) == -1)
throw runtime_error(format("unable to listen on socket '{}'", addr.sun_path)); 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; sockaddr_un client_addr;
socklen_t client_addr_len = sizeof(sockaddr_un); socklen_t client_addr_len = sizeof(sockaddr_un);
int sock = accept(watcher.fd(), (sockaddr*) &client_addr, 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_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) bool Server::rename_session(StringView name)

View File

@ -158,8 +158,8 @@ std::pair<String, int> ShellManager::eval(
struct PipeReader : FDWatcher struct PipeReader : FDWatcher
{ {
PipeReader(Pipe& pipe, String& contents) PipeReader(Pipe& pipe, String& contents)
: FDWatcher(pipe.read_fd(), : FDWatcher(pipe.read_fd(), FdEvents::Read,
[&contents, &pipe](FDWatcher& watcher, EventMode) { [&contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) {
char buffer[1024]; char buffer[1024];
size_t size = ::read(pipe.read_fd(), buffer, 1024); size_t size = ::read(pipe.read_fd(), buffer, 1024);
if (size <= 0) if (size <= 0)