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