Reopen pipe path on EOF
This commit is contained in:
parent
77b9cffaf8
commit
386eb57ba7
@ -40,6 +40,10 @@ struct UVHandleGeneric {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uv_loop_t* loop() const {
|
||||||
|
return handle->loop;
|
||||||
|
}
|
||||||
|
|
||||||
void close() {
|
void close() {
|
||||||
if (handle && !uv_is_closing((uv_handle_t*)handle)) {
|
if (handle && !uv_is_closing((uv_handle_t*)handle)) {
|
||||||
uv_close((uv_handle_t*)handle, close_callback);
|
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*> {
|
struct PipeHandle : public UVHandleGeneric<uv_pipe_t, uv_stream_t, ssize_t, const uv_buf_t*> {
|
||||||
PipeHandle(
|
PipeHandle(uv_loop_t* loop, const string& path, function<void(const string)> fun, function<void(void)> eof_cb,
|
||||||
uv_loop_t* loop, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
function<void(int)> err_cb);
|
||||||
void start(int fd);
|
void start();
|
||||||
void read_cb(ssize_t nread, const uv_buf_t* buf);
|
void read_cb(ssize_t nread, const uv_buf_t* buf);
|
||||||
|
|
||||||
function<void(const string)> func;
|
function<void(const string)> func;
|
||||||
function<void(void)> eof_cb;
|
function<void(void)> eof_cb;
|
||||||
function<void(int)> err_cb;
|
function<void(int)> err_cb;
|
||||||
int fd;
|
int fd;
|
||||||
|
string path;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimerHandle : public UVHandle<uv_timer_t> {
|
struct TimerHandle : public UVHandle<uv_timer_t> {
|
||||||
@ -129,7 +134,8 @@ class eventloop {
|
|||||||
void signal_handle(int signum, function<void(int)> fun);
|
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 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 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);
|
void timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun);
|
||||||
AsyncHandle_t async_handle(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);
|
explicit ipc(signal_emitter& emitter, const logger& logger);
|
||||||
~ipc();
|
~ipc();
|
||||||
|
|
||||||
|
string get_path() const;
|
||||||
|
|
||||||
void receive_data(string buf);
|
void receive_data(string buf);
|
||||||
void receive_eof();
|
void receive_eof();
|
||||||
int get_file_descriptor() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
signal_emitter& m_sig;
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
|
|
||||||
string m_path{};
|
string m_path{};
|
||||||
int m_fd;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer for the currently received IPC message.
|
* Buffer for the currently received IPC message.
|
||||||
|
@ -260,7 +260,7 @@ void controller::read_events(bool confwatch) {
|
|||||||
|
|
||||||
if (m_ipc) {
|
if (m_ipc) {
|
||||||
eloop->pipe_handle(
|
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]() { m_ipc->receive_eof(); },
|
||||||
[this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); });
|
[this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); });
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "errors.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,37 +97,54 @@ void FSEventHandle::fs_event_cb(const char* path, int events, int status) {
|
|||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// PipeHandle {{{
|
// PipeHandle {{{
|
||||||
PipeHandle::PipeHandle(
|
PipeHandle::PipeHandle(uv_loop_t* loop, const string& path, function<void(const string)> fun,
|
||||||
uv_loop_t* loop, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb)
|
function<void(void)> eof_cb, function<void(int)> err_cb)
|
||||||
: UVHandleGeneric([&](ssize_t nread, const uv_buf_t* buf) { read_cb(nread, buf); })
|
: UVHandleGeneric([&](ssize_t nread, const uv_buf_t* buf) { read_cb(nread, buf); })
|
||||||
, func(fun)
|
, func(fun)
|
||||||
, eof_cb(eof_cb)
|
, eof_cb(eof_cb)
|
||||||
, err_cb(err_cb) {
|
, err_cb(err_cb)
|
||||||
|
, path(path) {
|
||||||
UV(uv_pipe_init, loop, handle, false);
|
UV(uv_pipe_init, loop, handle, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipeHandle::start(int fd) {
|
void PipeHandle::start() {
|
||||||
this->fd = fd;
|
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_pipe_open, handle, fd);
|
||||||
UV(uv_read_start, (uv_stream_t*)handle, alloc_cb, callback);
|
UV(uv_read_start, (uv_stream_t*)handle, alloc_cb, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipeHandle::read_cb(ssize_t nread, const uv_buf_t* buf) {
|
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) {
|
if (nread > 0) {
|
||||||
func(string(buf->base, nread));
|
func(string(buf_ptr.get(), nread));
|
||||||
} else if (nread < 0) {
|
} else if (nread < 0) {
|
||||||
if (nread != UV_EOF) {
|
if (nread != UV_EOF) {
|
||||||
close();
|
close();
|
||||||
err_cb(nread);
|
err_cb(nread);
|
||||||
} else {
|
} else {
|
||||||
eof_cb();
|
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(
|
void eventloop::pipe_handle(
|
||||||
int fd, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb) {
|
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(), fun, eof_cb, err_cb));
|
m_pipe_handles.emplace_back(std::make_unique<PipeHandle>(get(), path, fun, eof_cb, err_cb));
|
||||||
m_pipe_handles.back()->start(fd);
|
m_pipe_handles.back()->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun) {
|
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) {
|
if (mkfifo(m_path.c_str(), 0666) == -1) {
|
||||||
throw system_error("Failed to create ipc channel");
|
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);
|
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
|
* Deconstruct ipc handler
|
||||||
*/
|
*/
|
||||||
ipc::~ipc() {
|
ipc::~ipc() {
|
||||||
if (!m_path.empty()) {
|
m_log.trace("ipc: Removing file handle at: %s", m_path);
|
||||||
m_log.trace("ipc: Removing file handle");
|
|
||||||
unlink(m_path.c_str());
|
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
|
POLYBAR_NS_END
|
||||||
|
Loading…
Reference in New Issue
Block a user