2021-02-20 15:26:45 -05:00
|
|
|
#include "components/eventloop.hpp"
|
|
|
|
|
2021-09-12 16:48:27 -04:00
|
|
|
#include <cassert>
|
|
|
|
|
2021-09-13 13:56:24 -04:00
|
|
|
#include "errors.hpp"
|
|
|
|
|
2021-09-13 14:19:00 -04:00
|
|
|
#if !(UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 3)
|
|
|
|
#error "Polybar requires libuv 1.x and at least version 1.3"
|
|
|
|
#endif
|
|
|
|
|
2021-02-20 15:26:45 -05:00
|
|
|
POLYBAR_NS
|
|
|
|
|
2021-09-12 16:28:27 -04:00
|
|
|
/**
|
|
|
|
* Closes the given wrapper.
|
|
|
|
*
|
|
|
|
* We have to have distinct cases for all types because we can't just cast to `UVHandleGeneric` without template
|
|
|
|
* arguments.
|
|
|
|
*/
|
|
|
|
void close_callback(uv_handle_t* handle) {
|
|
|
|
switch (handle->type) {
|
|
|
|
case UV_ASYNC:
|
2021-09-13 12:16:00 -04:00
|
|
|
static_cast<AsyncHandle*>(handle->data)->cleanup_resources();
|
2021-09-12 16:28:27 -04:00
|
|
|
break;
|
|
|
|
case UV_FS_EVENT:
|
2021-09-13 12:16:00 -04:00
|
|
|
static_cast<FSEventHandle*>(handle->data)->cleanup_resources();
|
2021-09-12 16:28:27 -04:00
|
|
|
break;
|
|
|
|
case UV_POLL:
|
2021-09-13 12:16:00 -04:00
|
|
|
static_cast<PollHandle*>(handle->data)->cleanup_resources();
|
2021-09-12 16:28:27 -04:00
|
|
|
break;
|
|
|
|
case UV_TIMER:
|
2021-09-13 12:16:00 -04:00
|
|
|
static_cast<TimerHandle*>(handle->data)->cleanup_resources();
|
2021-09-12 16:28:27 -04:00
|
|
|
break;
|
|
|
|
case UV_SIGNAL:
|
2021-09-13 12:16:00 -04:00
|
|
|
static_cast<SignalHandle*>(handle->data)->cleanup_resources();
|
2021-09-12 16:28:27 -04:00
|
|
|
break;
|
|
|
|
case UV_NAMED_PIPE:
|
2021-09-13 12:16:00 -04:00
|
|
|
static_cast<PipeHandle*>(handle->data)->cleanup_resources();
|
2021-09-12 16:28:27 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void alloc_cb(uv_handle_t*, size_t, uv_buf_t* buf) {
|
|
|
|
buf->base = new char[BUFSIZ];
|
|
|
|
buf->len = BUFSIZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignalHandle {{{
|
2021-09-13 13:19:39 -04:00
|
|
|
SignalHandle::SignalHandle(uv_loop_t* loop, function<void(int)> fun) : UVHandle(fun) {
|
2021-09-12 16:28:27 -04:00
|
|
|
UV(uv_signal_init, loop, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SignalHandle::start(int signum) {
|
|
|
|
UV(uv_signal_start, handle, callback, signum);
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
|
|
|
|
// PollHandle {{{
|
2021-09-13 13:19:39 -04:00
|
|
|
PollHandle::PollHandle(uv_loop_t* loop, int fd, function<void(uv_poll_event)> fun, function<void(int)> err_cb)
|
2021-09-13 12:16:00 -04:00
|
|
|
: UVHandle([this](int status, int events) { poll_cb(status, events); }), func(fun), err_cb(err_cb) {
|
2021-09-12 16:28:27 -04:00
|
|
|
UV(uv_poll_init, loop, handle, fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PollHandle::start(int events) {
|
|
|
|
UV(uv_poll_start, handle, events, callback);
|
|
|
|
}
|
2021-09-13 12:16:00 -04:00
|
|
|
|
|
|
|
void PollHandle::poll_cb(int status, int events) {
|
|
|
|
if (status < 0) {
|
|
|
|
close();
|
|
|
|
err_cb(status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
func((uv_poll_event)events);
|
|
|
|
}
|
2021-09-12 16:28:27 -04:00
|
|
|
// }}}
|
|
|
|
|
|
|
|
// FSEventHandle {{{
|
2021-09-13 13:19:39 -04:00
|
|
|
FSEventHandle::FSEventHandle(uv_loop_t* loop, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb)
|
2021-09-13 12:16:00 -04:00
|
|
|
: UVHandle([this](const char* path, int events, int status) { fs_event_cb(path, events, status); })
|
|
|
|
, func(fun)
|
|
|
|
, err_cb(err_cb) {
|
2021-09-12 16:28:27 -04:00
|
|
|
UV(uv_fs_event_init, loop, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSEventHandle::start(const string& path) {
|
|
|
|
UV(uv_fs_event_start, handle, callback, path.c_str(), 0);
|
|
|
|
}
|
2021-09-13 12:16:00 -04:00
|
|
|
|
|
|
|
void FSEventHandle::fs_event_cb(const char* path, int events, int status) {
|
|
|
|
if (status < 0) {
|
|
|
|
close();
|
|
|
|
err_cb(status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
func(path, (uv_fs_event)events);
|
|
|
|
}
|
2021-09-12 16:28:27 -04:00
|
|
|
// }}}
|
|
|
|
|
|
|
|
// PipeHandle {{{
|
2021-09-13 13:56:24 -04:00
|
|
|
PipeHandle::PipeHandle(uv_loop_t* loop, const string& path, function<void(const string)> fun,
|
|
|
|
function<void(void)> eof_cb, function<void(int)> err_cb)
|
2021-09-13 12:30:11 -04:00
|
|
|
: UVHandleGeneric([&](ssize_t nread, const uv_buf_t* buf) { read_cb(nread, buf); })
|
|
|
|
, func(fun)
|
|
|
|
, eof_cb(eof_cb)
|
2021-09-13 13:56:24 -04:00
|
|
|
, err_cb(err_cb)
|
|
|
|
, path(path) {
|
2021-09-12 16:28:27 -04:00
|
|
|
UV(uv_pipe_init, loop, handle, false);
|
|
|
|
}
|
|
|
|
|
2021-09-13 13:56:24 -04:00
|
|
|
void PipeHandle::start() {
|
|
|
|
if ((fd = open(path.c_str(), O_RDONLY | O_NONBLOCK)) == -1) {
|
|
|
|
throw system_error("Failed to open pipe '" + path + "'");
|
|
|
|
}
|
2021-09-12 16:28:27 -04:00
|
|
|
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) {
|
2021-09-13 13:56:24 -04:00
|
|
|
/*
|
|
|
|
* Wrap pointer so that it gets automatically freed once the function returns (even with exceptions)
|
|
|
|
*/
|
|
|
|
auto buf_ptr = unique_ptr<char>(buf->base);
|
2021-09-12 16:28:27 -04:00
|
|
|
if (nread > 0) {
|
2021-09-13 13:56:24 -04:00
|
|
|
func(string(buf_ptr.get(), nread));
|
2021-09-12 16:28:27 -04:00
|
|
|
} else if (nread < 0) {
|
|
|
|
if (nread != UV_EOF) {
|
2021-09-13 12:30:11 -04:00
|
|
|
close();
|
|
|
|
err_cb(nread);
|
2021-09-12 16:28:27 -04:00
|
|
|
} else {
|
2021-09-12 17:26:24 -04:00
|
|
|
eof_cb();
|
2021-09-12 16:28:27 -04:00
|
|
|
|
2021-09-13 13:56:24 -04:00
|
|
|
/*
|
|
|
|
* 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();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-09-12 16:28:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
|
|
|
|
// TimerHandle {{{
|
2021-09-13 13:19:39 -04:00
|
|
|
TimerHandle::TimerHandle(uv_loop_t* loop, function<void(void)> fun) : UVHandle(fun) {
|
2021-09-12 16:28:27 -04:00
|
|
|
UV(uv_timer_init, loop, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimerHandle::start(uint64_t timeout, uint64_t repeat) {
|
|
|
|
UV(uv_timer_start, handle, callback, timeout, repeat);
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
|
|
|
|
// AsyncHandle {{{
|
2021-09-13 13:19:39 -04:00
|
|
|
AsyncHandle::AsyncHandle(uv_loop_t* loop, function<void(void)> fun) : UVHandle(fun) {
|
2021-09-12 16:28:27 -04:00
|
|
|
UV(uv_async_init, loop, handle, callback);
|
2021-02-20 15:26:45 -05:00
|
|
|
}
|
|
|
|
|
2021-09-12 16:28:27 -04:00
|
|
|
void AsyncHandle::send() {
|
|
|
|
UV(uv_async_send, handle);
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
|
|
|
|
// eventloop {{{
|
2021-03-01 18:00:24 -05:00
|
|
|
static void close_walk_cb(uv_handle_t* handle, void*) {
|
|
|
|
if (!uv_is_closing(handle)) {
|
2021-09-12 16:28:27 -04:00
|
|
|
uv_close(handle, close_callback);
|
2021-03-01 18:00:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Completely closes everything in the loop.
|
|
|
|
*
|
|
|
|
* After this function returns, uv_loop_close can be called.
|
|
|
|
*/
|
|
|
|
static void close_loop(uv_loop_t* loop) {
|
|
|
|
uv_walk(loop, close_walk_cb, nullptr);
|
2021-03-10 18:09:06 -05:00
|
|
|
UV(uv_run, loop, UV_RUN_DEFAULT);
|
2021-03-01 18:00:24 -05:00
|
|
|
}
|
|
|
|
|
2021-09-12 16:28:27 -04:00
|
|
|
eventloop::eventloop() {
|
|
|
|
m_loop = std::make_unique<uv_loop_t>();
|
|
|
|
UV(uv_loop_init, m_loop.get());
|
|
|
|
m_loop->data = this;
|
|
|
|
}
|
|
|
|
|
2021-02-20 15:26:45 -05:00
|
|
|
eventloop::~eventloop() {
|
|
|
|
if (m_loop) {
|
2021-03-10 18:09:06 -05:00
|
|
|
try {
|
|
|
|
close_loop(m_loop.get());
|
|
|
|
UV(uv_loop_close, m_loop.get());
|
|
|
|
} catch (const std::exception& e) {
|
2021-09-12 09:42:30 -04:00
|
|
|
logger::make().err("%s", e.what());
|
2021-03-10 18:09:06 -05:00
|
|
|
}
|
2021-03-01 18:00:24 -05:00
|
|
|
|
|
|
|
m_loop.reset();
|
2021-02-20 15:26:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void eventloop::run() {
|
2021-03-10 18:09:06 -05:00
|
|
|
UV(uv_run, m_loop.get(), UV_RUN_DEFAULT);
|
2021-02-20 15:26:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void eventloop::stop() {
|
|
|
|
uv_stop(m_loop.get());
|
|
|
|
}
|
|
|
|
|
2021-09-12 16:28:27 -04:00
|
|
|
uv_loop_t* eventloop::get() const {
|
|
|
|
return m_loop.get();
|
|
|
|
}
|
|
|
|
|
2021-09-13 13:19:39 -04:00
|
|
|
void eventloop::signal_handle(int signum, function<void(int)> fun) {
|
2021-09-12 16:28:27 -04:00
|
|
|
m_sig_handles.emplace_back(std::make_unique<SignalHandle>(get(), fun));
|
|
|
|
m_sig_handles.back()->start(signum);
|
|
|
|
}
|
|
|
|
|
2021-09-13 13:19:39 -04:00
|
|
|
void eventloop::poll_handle(int events, int fd, function<void(uv_poll_event)> fun, function<void(int)> err_cb) {
|
2021-09-13 12:16:00 -04:00
|
|
|
m_poll_handles.emplace_back(std::make_unique<PollHandle>(get(), fd, fun, err_cb));
|
2021-09-12 16:28:27 -04:00
|
|
|
m_poll_handles.back()->start(events);
|
|
|
|
}
|
|
|
|
|
2021-09-13 13:19:39 -04:00
|
|
|
void eventloop::fs_event_handle(
|
|
|
|
const string& path, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb) {
|
2021-09-13 12:16:00 -04:00
|
|
|
m_fs_event_handles.emplace_back(std::make_unique<FSEventHandle>(get(), fun, err_cb));
|
2021-09-12 16:28:27 -04:00
|
|
|
m_fs_event_handles.back()->start(path);
|
|
|
|
}
|
|
|
|
|
2021-09-13 12:30:11 -04:00
|
|
|
void eventloop::pipe_handle(
|
2021-09-13 13:56:24 -04:00
|
|
|
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();
|
2021-09-12 16:28:27 -04:00
|
|
|
}
|
|
|
|
|
2021-09-13 13:19:39 -04:00
|
|
|
void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun) {
|
2021-09-12 16:28:27 -04:00
|
|
|
m_timer_handles.emplace_back(std::make_unique<TimerHandle>(get(), fun));
|
|
|
|
m_timer_handles.back()->start(timeout, repeat);
|
|
|
|
}
|
|
|
|
|
2021-09-13 13:19:39 -04:00
|
|
|
AsyncHandle_t eventloop::async_handle(function<void(void)> fun) {
|
2021-09-12 16:28:27 -04:00
|
|
|
m_async_handles.emplace_back(std::make_shared<AsyncHandle>(get(), fun));
|
|
|
|
return m_async_handles.back();
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
|
2021-02-20 15:26:45 -05:00
|
|
|
POLYBAR_NS_END
|