Reopen pipe path on EOF
This commit is contained in:
parent
77b9cffaf8
commit
386eb57ba7
@ -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<uv_fs_event_t, const char*, int, int> {
|
||||
};
|
||||
|
||||
struct PipeHandle : public UVHandleGeneric<uv_pipe_t, uv_stream_t, ssize_t, const uv_buf_t*> {
|
||||
PipeHandle(
|
||||
uv_loop_t* loop, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
||||
void start(int fd);
|
||||
PipeHandle(uv_loop_t* loop, const string& path, function<void(const string)> fun, function<void(void)> eof_cb,
|
||||
function<void(int)> err_cb);
|
||||
void start();
|
||||
void read_cb(ssize_t nread, const uv_buf_t* buf);
|
||||
|
||||
function<void(const string)> func;
|
||||
function<void(void)> eof_cb;
|
||||
function<void(int)> err_cb;
|
||||
int fd;
|
||||
string path;
|
||||
};
|
||||
|
||||
struct TimerHandle : public UVHandle<uv_timer_t> {
|
||||
@ -129,7 +134,8 @@ class eventloop {
|
||||
void signal_handle(int signum, function<void(int)> fun);
|
||||
void poll_handle(int events, int fd, function<void(uv_poll_event)> fun, function<void(int)> err_cb);
|
||||
void fs_event_handle(const string& path, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb);
|
||||
void pipe_handle(int fd, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
||||
void pipe_handle(
|
||||
const string& path, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
||||
void timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun);
|
||||
AsyncHandle_t async_handle(function<void(void)> fun);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)); });
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#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<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb)
|
||||
PipeHandle::PipeHandle(uv_loop_t* loop, const string& path, function<void(const string)> fun,
|
||||
function<void(void)> eof_cb, function<void(int)> 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<char>(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<PipeHandle*>(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<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb) {
|
||||
m_pipe_handles.emplace_back(std::make_unique<PipeHandle>(get(), fun, eof_cb, err_cb));
|
||||
m_pipe_handles.back()->start(fd);
|
||||
const string& path, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb) {
|
||||
m_pipe_handles.emplace_back(std::make_unique<PipeHandle>(get(), path, fun, eof_cb, err_cb));
|
||||
m_pipe_handles.back()->start();
|
||||
}
|
||||
|
||||
void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun) {
|
||||
|
@ -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");
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user