From 386eb57ba7a14a42932d39971bff228c03a8b934 Mon Sep 17 00:00:00 2001 From: patrick96 Date: Mon, 13 Sep 2021 19:56:24 +0200 Subject: [PATCH] Reopen pipe path on EOF --- include/components/eventloop.hpp | 14 ++++++--- include/components/ipc.hpp | 4 +-- src/components/controller.cpp | 2 +- src/components/eventloop.cpp | 49 ++++++++++++++++++++++---------- src/components/ipc.cpp | 22 ++++---------- 5 files changed, 53 insertions(+), 38 deletions(-) diff --git a/include/components/eventloop.hpp b/include/components/eventloop.hpp index 441cf951..4798a3e1 100644 --- a/include/components/eventloop.hpp +++ b/include/components/eventloop.hpp @@ -40,6 +40,10 @@ struct UVHandleGeneric { close(); } + uv_loop_t* loop() const { + return handle->loop; + } + void close() { if (handle && !uv_is_closing((uv_handle_t*)handle)) { uv_close((uv_handle_t*)handle, close_callback); @@ -91,15 +95,16 @@ struct FSEventHandle : public UVHandle { }; struct PipeHandle : public UVHandleGeneric { - PipeHandle( - uv_loop_t* loop, function fun, function eof_cb, function err_cb); - void start(int fd); + PipeHandle(uv_loop_t* loop, const string& path, function fun, function eof_cb, + function err_cb); + void start(); void read_cb(ssize_t nread, const uv_buf_t* buf); function func; function eof_cb; function err_cb; int fd; + string path; }; struct TimerHandle : public UVHandle { @@ -129,7 +134,8 @@ class eventloop { void signal_handle(int signum, function fun); void poll_handle(int events, int fd, function fun, function err_cb); void fs_event_handle(const string& path, function fun, function err_cb); - void pipe_handle(int fd, function fun, function eof_cb, function err_cb); + void pipe_handle( + const string& path, function fun, function eof_cb, function err_cb); void timer_handle(uint64_t timeout, uint64_t repeat, function fun); AsyncHandle_t async_handle(function fun); diff --git a/include/components/ipc.hpp b/include/components/ipc.hpp index f6082371..1d376952 100644 --- a/include/components/ipc.hpp +++ b/include/components/ipc.hpp @@ -26,16 +26,16 @@ class ipc { explicit ipc(signal_emitter& emitter, const logger& logger); ~ipc(); + string get_path() const; + void receive_data(string buf); void receive_eof(); - int get_file_descriptor() const; private: signal_emitter& m_sig; const logger& m_log; string m_path{}; - int m_fd; /** * Buffer for the currently received IPC message. diff --git a/src/components/controller.cpp b/src/components/controller.cpp index f9ccc646..494e7f35 100644 --- a/src/components/controller.cpp +++ b/src/components/controller.cpp @@ -260,7 +260,7 @@ void controller::read_events(bool confwatch) { if (m_ipc) { eloop->pipe_handle( - m_ipc->get_file_descriptor(), [this](const string payload) { m_ipc->receive_data(payload); }, + m_ipc->get_path(), [this](const string payload) { m_ipc->receive_data(payload); }, [this]() { m_ipc->receive_eof(); }, [this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); }); } diff --git a/src/components/eventloop.cpp b/src/components/eventloop.cpp index 811939e2..6e4359ce 100644 --- a/src/components/eventloop.cpp +++ b/src/components/eventloop.cpp @@ -2,6 +2,8 @@ #include +#include "errors.hpp" + POLYBAR_NS /** @@ -95,37 +97,54 @@ void FSEventHandle::fs_event_cb(const char* path, int events, int status) { // }}} // PipeHandle {{{ -PipeHandle::PipeHandle( - uv_loop_t* loop, function fun, function eof_cb, function err_cb) +PipeHandle::PipeHandle(uv_loop_t* loop, const string& path, function fun, + function eof_cb, function err_cb) : UVHandleGeneric([&](ssize_t nread, const uv_buf_t* buf) { read_cb(nread, buf); }) , func(fun) , eof_cb(eof_cb) - , err_cb(err_cb) { + , err_cb(err_cb) + , path(path) { UV(uv_pipe_init, loop, handle, false); } -void PipeHandle::start(int fd) { - this->fd = fd; +void PipeHandle::start() { + if ((fd = open(path.c_str(), O_RDONLY | O_NONBLOCK)) == -1) { + throw system_error("Failed to open pipe '" + path + "'"); + } UV(uv_pipe_open, handle, fd); UV(uv_read_start, (uv_stream_t*)handle, alloc_cb, callback); } void PipeHandle::read_cb(ssize_t nread, const uv_buf_t* buf) { + /* + * Wrap pointer so that it gets automatically freed once the function returns (even with exceptions) + */ + auto buf_ptr = unique_ptr(buf->base); if (nread > 0) { - func(string(buf->base, nread)); + func(string(buf_ptr.get(), nread)); } else if (nread < 0) { if (nread != UV_EOF) { close(); err_cb(nread); } else { eof_cb(); - // TODO this causes constant EOFs - start(this->fd); - } - } - if (buf->base) { - delete[] buf->base; + /* + * This is a special case. + * + * Once we read EOF, we no longer receive events for the fd, so we close the entire handle and restart it with a + * new fd. + * + * We reuse the memory for the underlying uv handle + */ + if (!uv_is_closing((uv_handle_t*)handle)) { + uv_close((uv_handle_t*)handle, [](uv_handle_t* handle) { + PipeHandle* This = static_cast(handle->data); + UV(uv_pipe_init, This->loop(), This->handle, false); + This->start(); + }); + } + } } } // }}} @@ -215,9 +234,9 @@ void eventloop::fs_event_handle( } void eventloop::pipe_handle( - int fd, function fun, function eof_cb, function err_cb) { - m_pipe_handles.emplace_back(std::make_unique(get(), fun, eof_cb, err_cb)); - m_pipe_handles.back()->start(fd); + const string& path, function fun, function eof_cb, function err_cb) { + m_pipe_handles.emplace_back(std::make_unique(get(), path, fun, eof_cb, err_cb)); + m_pipe_handles.back()->start(); } void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function fun) { diff --git a/src/components/ipc.cpp b/src/components/ipc.cpp index bc821249..da2a948d 100644 --- a/src/components/ipc.cpp +++ b/src/components/ipc.cpp @@ -39,11 +39,6 @@ ipc::ipc(signal_emitter& emitter, const logger& logger) : m_sig(emitter), m_log( if (mkfifo(m_path.c_str(), 0666) == -1) { throw system_error("Failed to create ipc channel"); } - - if ((m_fd = open(m_path.c_str(), O_RDONLY | O_NONBLOCK)) == -1) { - throw system_error("Failed to open pipe '" + m_path + "'"); - } - m_log.info("Created ipc channel at: %s", m_path); } @@ -51,10 +46,12 @@ ipc::ipc(signal_emitter& emitter, const logger& logger) : m_sig(emitter), m_log( * Deconstruct ipc handler */ ipc::~ipc() { - if (!m_path.empty()) { - m_log.trace("ipc: Removing file handle"); - unlink(m_path.c_str()); - } + m_log.trace("ipc: Removing file handle at: %s", m_path); + unlink(m_path.c_str()); +} + +string ipc::get_path() const { + return m_path; } /** @@ -87,11 +84,4 @@ void ipc::receive_eof() { } } -/** - * Get the file descriptor to the ipc channel - */ -int ipc::get_file_descriptor() const { - return m_fd; -} - POLYBAR_NS_END