Use a select based event handling and fix deadlock
This commit is contained in:
parent
def4221ac7
commit
0517a19e6d
|
@ -95,7 +95,7 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll)
|
||||||
|
|
||||||
auto watcher_deleter = [buffer](FDWatcher* watcher) {
|
auto watcher_deleter = [buffer](FDWatcher* watcher) {
|
||||||
kak_assert(buffer->flags() & Buffer::Flags::Fifo);
|
kak_assert(buffer->flags() & Buffer::Flags::Fifo);
|
||||||
close(watcher->fd());
|
watcher->close_fd();
|
||||||
buffer->run_hook_in_own_context("BufCloseFifo", "");
|
buffer->run_hook_in_own_context("BufCloseFifo", "");
|
||||||
buffer->flags() &= ~Buffer::Flags::Fifo;
|
buffer->flags() &= ~Buffer::Flags::Fifo;
|
||||||
watcher->~FDWatcher();
|
watcher->~FDWatcher();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "event_manager.hh"
|
#include "event_manager.hh"
|
||||||
|
|
||||||
#include <poll.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,12 @@ void FDWatcher::run(EventMode mode)
|
||||||
m_callback(*this, mode);
|
m_callback(*this, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FDWatcher::close_fd()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
m_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
Timer::Timer(TimePoint date, Callback callback, EventMode mode)
|
Timer::Timer(TimePoint date, Callback callback, EventMode mode)
|
||||||
: m_date{date}, m_callback{std::move(callback)}, m_mode(mode)
|
: m_date{date}, m_callback{std::move(callback)}, m_mode(mode)
|
||||||
{
|
{
|
||||||
|
@ -47,7 +53,7 @@ void Timer::run(EventMode mode)
|
||||||
|
|
||||||
EventManager::EventManager()
|
EventManager::EventManager()
|
||||||
{
|
{
|
||||||
m_forced_fd.reserve(4);
|
FD_ZERO(&m_forced_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager::~EventManager()
|
EventManager::~EventManager()
|
||||||
|
@ -58,10 +64,18 @@ EventManager::~EventManager()
|
||||||
|
|
||||||
void EventManager::handle_next_events(EventMode mode)
|
void EventManager::handle_next_events(EventMode mode)
|
||||||
{
|
{
|
||||||
std::vector<pollfd> events;
|
int max_fd = 0;
|
||||||
events.reserve(m_fd_watchers.size());
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
for (auto& watcher : m_fd_watchers)
|
for (auto& watcher : m_fd_watchers)
|
||||||
events.emplace_back(pollfd{ watcher->fd(), POLLIN | POLLPRI, 0 });
|
{
|
||||||
|
const int fd = watcher->fd();
|
||||||
|
if (fd != -1)
|
||||||
|
{
|
||||||
|
max_fd = std::max(fd, max_fd);
|
||||||
|
FD_SET(fd, &rfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TimePoint next_timer = TimePoint::max();
|
TimePoint next_timer = TimePoint::max();
|
||||||
for (auto& timer : m_timers)
|
for (auto& timer : m_timers)
|
||||||
|
@ -70,21 +84,23 @@ void EventManager::handle_next_events(EventMode mode)
|
||||||
next_timer = timer->next_date();
|
next_timer = timer->next_date();
|
||||||
}
|
}
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto timeout = duration_cast<milliseconds>(next_timer - Clock::now()).count();
|
auto timeout = duration_cast<microseconds>(next_timer - Clock::now()).count();
|
||||||
poll(events.data(), events.size(), timeout < INT_MAX ? (int)timeout : INT_MAX);
|
|
||||||
|
|
||||||
// gather forced fds *after* poll, so that signal handlers can write to
|
constexpr auto us = 1000000000ll;
|
||||||
|
timeval tv{ (long)(timeout / us), (long)(timeout % us) };
|
||||||
|
int res = select(max_fd + 1, &rfds, nullptr, nullptr, &tv);
|
||||||
|
|
||||||
|
// copy forced fds *after* poll, so that signal handlers can write to
|
||||||
// m_forced_fd, interupt poll, and directly be serviced.
|
// m_forced_fd, interupt poll, and directly be serviced.
|
||||||
std::vector<int> forced;
|
fd_set forced = m_forced_fd;
|
||||||
std::swap(forced, m_forced_fd);
|
FD_ZERO(&m_forced_fd);
|
||||||
|
|
||||||
for (auto& event : events)
|
for (int fd = 0; fd < max_fd + 1; ++fd)
|
||||||
{
|
{
|
||||||
const int fd = event.fd;
|
if ((res > 0 and FD_ISSET(fd, &rfds)) or FD_ISSET(fd, &forced))
|
||||||
if (event.revents or contains(forced, fd))
|
|
||||||
{
|
{
|
||||||
auto it = find_if(m_fd_watchers,
|
auto it = find_if(m_fd_watchers,
|
||||||
[fd](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(mode);
|
||||||
}
|
}
|
||||||
|
@ -100,7 +116,7 @@ void EventManager::handle_next_events(EventMode mode)
|
||||||
|
|
||||||
void EventManager::force_signal(int fd)
|
void EventManager::force_signal(int fd)
|
||||||
{
|
{
|
||||||
m_forced_fd.push_back(fd);
|
FD_SET(fd, &m_forced_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -28,6 +30,9 @@ public:
|
||||||
|
|
||||||
int fd() const { return m_fd; }
|
int fd() const { return m_fd; }
|
||||||
void run(EventMode mode);
|
void run(EventMode mode);
|
||||||
|
|
||||||
|
void close_fd();
|
||||||
|
bool closed() const { return m_fd == -1; }
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int m_fd;
|
int m_fd;
|
||||||
|
@ -80,7 +85,7 @@ private:
|
||||||
friend class Timer;
|
friend class Timer;
|
||||||
std::unordered_set<FDWatcher*> m_fd_watchers;
|
std::unordered_set<FDWatcher*> m_fd_watchers;
|
||||||
std::unordered_set<Timer*> m_timers;
|
std::unordered_set<Timer*> m_timers;
|
||||||
std::vector<int> m_forced_fd;
|
fd_set m_forced_fd;
|
||||||
|
|
||||||
TimePoint m_last;
|
TimePoint m_last;
|
||||||
};
|
};
|
||||||
|
|
|
@ -295,7 +295,7 @@ RemoteUI::~RemoteUI()
|
||||||
{
|
{
|
||||||
write_debug("remote client disconnected: " +
|
write_debug("remote client disconnected: " +
|
||||||
to_string(m_socket_watcher.fd()));
|
to_string(m_socket_watcher.fd()));
|
||||||
close(m_socket_watcher.fd());
|
m_socket_watcher.close_fd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteUI::menu_show(memoryview<String> choices,
|
void RemoteUI::menu_show(memoryview<String> choices,
|
||||||
|
@ -646,7 +646,7 @@ Server::Server(String session_name)
|
||||||
void Server::close_session()
|
void Server::close_session()
|
||||||
{
|
{
|
||||||
unlink(("/tmp/kak-" + m_session).c_str());
|
unlink(("/tmp/kak-" + m_session).c_str());
|
||||||
close(m_listener->fd());
|
m_listener->close_fd();
|
||||||
m_listener.reset();
|
m_listener.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,27 +66,20 @@ String ShellManager::pipe(StringView input,
|
||||||
|
|
||||||
String error;
|
String error;
|
||||||
{
|
{
|
||||||
auto pipe_reader = [](String& output, bool& closed) {
|
auto pipe_reader = [](String& output) {
|
||||||
return [&output, &closed](FDWatcher& watcher, EventMode) {
|
return [&output](FDWatcher& watcher, EventMode) {
|
||||||
if (closed)
|
|
||||||
return;
|
|
||||||
const int fd = watcher.fd();
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
size_t size = read(fd, buffer, 1024);
|
size_t size = read(watcher.fd(), buffer, 1024);
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
{
|
watcher.close_fd();
|
||||||
close(fd);
|
|
||||||
closed = true;
|
|
||||||
}
|
|
||||||
output += String(buffer, buffer+size);
|
output += String(buffer, buffer+size);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool stdout_closed = false, stderr_closed = false;
|
FDWatcher stdout_watcher{read_pipe[0], pipe_reader(output)};
|
||||||
FDWatcher stdout_watcher{read_pipe[0], pipe_reader(output, stdout_closed)};
|
FDWatcher stderr_watcher{error_pipe[0], pipe_reader(error)};
|
||||||
FDWatcher stderr_watcher{error_pipe[0], pipe_reader(error, stderr_closed)};
|
|
||||||
|
|
||||||
while (not stdout_closed or not stderr_closed)
|
while (not stdout_watcher.closed() and not stderr_watcher.closed())
|
||||||
EventManager::instance().handle_next_events(EventMode::Urgent);
|
EventManager::instance().handle_next_events(EventMode::Urgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user