From 511e73b3b5efaec7482b697d6be5f935175ad108 Mon Sep 17 00:00:00 2001 From: patrick96 Date: Sun, 12 Sep 2021 22:28:27 +0200 Subject: [PATCH] Close handles in destructor --- include/components/eventloop.hpp | 170 ++++++++----------------------- src/components/eventloop.cpp | 170 ++++++++++++++++++++++++++++++- 2 files changed, 210 insertions(+), 130 deletions(-) diff --git a/include/components/eventloop.hpp b/include/components/eventloop.hpp index 1394c5e7..8d94045a 100644 --- a/include/components/eventloop.hpp +++ b/include/components/eventloop.hpp @@ -22,15 +22,7 @@ POLYBAR_NS } \ } while (0); -template -struct cb_helper { - std::function func; - - static void callback(H* context, Args... args) { - const auto unpackedThis = static_cast(context->data); - return unpackedThis->func(std::forward(args)...); - } -}; +void close_callback(uv_handle_t*); /** * \tparam H Type of the handle @@ -39,13 +31,31 @@ struct cb_helper { template struct UVHandleGeneric { UVHandleGeneric(std::function fun) { - handle = std::make_unique(); - cb = cb_helper{fun}; - handle->data = &cb; + handle = new H; + handle->data = this; + this->func = fun; } - std::unique_ptr handle; - cb_helper cb; + ~UVHandleGeneric() { + if (handle && !uv_is_closing((uv_handle_t*)handle)) { + uv_close((uv_handle_t*)handle, close_callback); + } + } + + void close() { + if (handle) { + delete handle; + handle = nullptr; + } + } + + static void callback(I* context, Args... args) { + const auto unpackedThis = static_cast(context->data); + return unpackedThis->func(std::forward(args)...); + } + + H* handle; + std::function func; }; template @@ -54,98 +64,37 @@ struct UVHandle : public UVHandleGeneric { }; struct SignalHandle : public UVHandle { - SignalHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { - UV(uv_signal_init, loop, handle.get()); - } - - void start(int signum) { - UV(uv_signal_start, handle.get(), cb.callback, signum); - } + SignalHandle(uv_loop_t* loop, std::function fun); + void start(int signum); }; struct PollHandle : public UVHandle { - // TODO wrap callback and handle status - PollHandle(uv_loop_t* loop, int fd, std::function fun) : UVHandle(fun) { - UV(uv_poll_init, loop, handle.get(), fd); - } - - void start(int events) { - UV(uv_poll_start, handle.get(), events, &cb.callback); - } + PollHandle(uv_loop_t* loop, int fd, std::function fun); + void start(int events); }; struct FSEventHandle : public UVHandle { - // TODO wrap callback and handle status - FSEventHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { - UV(uv_fs_event_init, loop, handle.get()); - } - - void start(const string& path) { - UV(uv_fs_event_start, handle.get(), &cb.callback, path.c_str(), 0); - } + FSEventHandle(uv_loop_t* loop, std::function fun); + void start(const string& path); }; struct PipeHandle : public UVHandleGeneric { + PipeHandle(uv_loop_t* loop, std::function fun); + void start(int fd); + void read_cb(ssize_t nread, const uv_buf_t* buf); + std::function func; - int fd; - - PipeHandle(uv_loop_t* loop, std::function fun) - : UVHandleGeneric([&](ssize_t nread, const uv_buf_t* buf) { read_cb(nread, buf); }), func(fun) { - UV(uv_pipe_init, loop, handle.get(), false); - } - - void start(int fd) { - this->fd = fd; - UV(uv_pipe_open, handle.get(), fd); - UV(uv_read_start, (uv_stream_t*)handle.get(), alloc_cb, &cb.callback); - } - - static void alloc_cb(uv_handle_t*, size_t, uv_buf_t* buf) { - buf->base = new char[BUFSIZ]; - buf->len = BUFSIZ; - } - - void read_cb(ssize_t nread, const uv_buf_t* buf) { - auto log = logger::make(); - if (nread > 0) { - string payload = string(buf->base, nread); - log.notice("Bytes read: %d: '%s'", nread, payload); - func(payload); - } else if (nread < 0) { - if (nread != UV_EOF) { - log.err("Read error: %s", uv_err_name(nread)); - uv_close((uv_handle_t*)handle.get(), nullptr); - } else { - // TODO this causes constant EOFs - start(this->fd); - } - } - - if (buf->base) { - delete[] buf->base; - } - } }; struct TimerHandle : public UVHandle { - TimerHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { - UV(uv_timer_init, loop, handle.get()); - } - - void start(uint64_t timeout, uint64_t repeat) { - UV(uv_timer_start, handle.get(), &cb.callback, timeout, repeat); - } + TimerHandle(uv_loop_t* loop, std::function fun); + void start(uint64_t timeout, uint64_t repeat); }; struct AsyncHandle : public UVHandle { - AsyncHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { - UV(uv_async_init, loop, handle.get(), &cb.callback); - } - - void send() { - UV(uv_async_send, handle.get()); - } + AsyncHandle(uv_loop_t* loop, std::function fun); + void send(); }; using SignalHandle_t = std::unique_ptr; @@ -160,46 +109,17 @@ class eventloop { public: eventloop(); ~eventloop(); - void run(); - void stop(); - - void signal_handler(int signum, std::function fun) { - m_sig_handles.emplace_back(std::make_unique(get(), fun)); - m_sig_handles.back()->start(signum); - } - - void poll_handler(int events, int fd, std::function fun) { - m_poll_handles.emplace_back(std::make_unique(get(), fd, fun)); - m_poll_handles.back()->start(events); - } - - void fs_event_handler(const string& path, std::function fun) { - m_fs_event_handles.emplace_back(std::make_unique(get(), fun)); - m_fs_event_handles.back()->start(path); - } - - void pipe_handle(int fd, std::function fun) { - m_pipe_handles.emplace_back(std::make_unique(get(), fun)); - m_pipe_handles.back()->start(fd); - } - - void timer_handle(uint64_t timeout, uint64_t repeat, std::function fun) { - m_timer_handles.emplace_back(std::make_unique(get(), fun)); - // Trigger a single screenshot after 3 seconds - m_timer_handles.back()->start(timeout, repeat); - } - - AsyncHandle_t async_handle(std::function fun) { - m_async_handles.emplace_back(std::make_shared(get(), fun)); - return m_async_handles.back(); - } + void signal_handler(int signum, std::function fun); + void poll_handler(int events, int fd, std::function fun); + void fs_event_handler(const string& path, std::function fun); + void pipe_handle(int fd, std::function fun); + void timer_handle(uint64_t timeout, uint64_t repeat, std::function fun); + AsyncHandle_t async_handle(std::function fun); protected: - uv_loop_t* get() const { - return m_loop.get(); - } + uv_loop_t* get() const; private: std::unique_ptr m_loop{nullptr}; diff --git a/src/components/eventloop.cpp b/src/components/eventloop.cpp index c70254bc..7817a221 100644 --- a/src/components/eventloop.cpp +++ b/src/components/eventloop.cpp @@ -2,15 +2,134 @@ POLYBAR_NS -eventloop::eventloop() { - m_loop = std::make_unique(); - UV(uv_loop_init, m_loop.get()); - m_loop->data = this; +/** + * 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: + static_cast(handle->data)->close(); + break; + case UV_FS_EVENT: + static_cast(handle->data)->close(); + break; + case UV_POLL: + static_cast(handle->data)->close(); + break; + case UV_TIMER: + static_cast(handle->data)->close(); + break; + case UV_SIGNAL: + static_cast(handle->data)->close(); + break; + case UV_NAMED_PIPE: + static_cast(handle->data)->close(); + 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 {{{ +SignalHandle::SignalHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { + UV(uv_signal_init, loop, handle); +} + +void SignalHandle::start(int signum) { + UV(uv_signal_start, handle, callback, signum); +} +// }}} + +// PollHandle {{{ +// TODO wrap callback and handle status +PollHandle::PollHandle(uv_loop_t* loop, int fd, std::function fun) : UVHandle(fun) { + UV(uv_poll_init, loop, handle, fd); +} + +void PollHandle::start(int events) { + UV(uv_poll_start, handle, events, callback); +} +// }}} + +// FSEventHandle {{{ +// TODO wrap callback and handle status +FSEventHandle::FSEventHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { + UV(uv_fs_event_init, loop, handle); +} + +void FSEventHandle::start(const string& path) { + UV(uv_fs_event_start, handle, callback, path.c_str(), 0); +} +// }}} + +// PipeHandle {{{ +PipeHandle::PipeHandle(uv_loop_t* loop, std::function fun) + : UVHandleGeneric([&](ssize_t nread, const uv_buf_t* buf) { read_cb(nread, buf); }), func(fun) { + UV(uv_pipe_init, loop, handle, false); +} + +void PipeHandle::start(int fd) { + this->fd = fd; + 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) { + auto log = logger::make(); + if (nread > 0) { + string payload = string(buf->base, nread); + // TODO lower logging level + log.notice("Bytes read: %d: '%s'", nread, payload); + func(payload); + } else if (nread < 0) { + if (nread != UV_EOF) { + // TODO maybe handle this differently. exception? + log.err("Read error: %s", uv_err_name(nread)); + uv_close((uv_handle_t*)handle, nullptr); + } else { + // TODO this causes constant EOFs + start(this->fd); + } + } + + if (buf->base) { + delete[] buf->base; + } +} +// }}} + +// TimerHandle {{{ +TimerHandle::TimerHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { + UV(uv_timer_init, loop, handle); +} + +void TimerHandle::start(uint64_t timeout, uint64_t repeat) { + UV(uv_timer_start, handle, callback, timeout, repeat); +} +// }}} + +// AsyncHandle {{{ +AsyncHandle::AsyncHandle(uv_loop_t* loop, std::function fun) : UVHandle(fun) { + UV(uv_async_init, loop, handle, callback); +} + +void AsyncHandle::send() { + UV(uv_async_send, handle); +} +// }}} + +// eventloop {{{ static void close_walk_cb(uv_handle_t* handle, void*) { if (!uv_is_closing(handle)) { - uv_close(handle, nullptr); + uv_close(handle, close_callback); } } @@ -24,6 +143,12 @@ static void close_loop(uv_loop_t* loop) { UV(uv_run, loop, UV_RUN_DEFAULT); } +eventloop::eventloop() { + m_loop = std::make_unique(); + UV(uv_loop_init, m_loop.get()); + m_loop->data = this; +} + eventloop::~eventloop() { if (m_loop) { try { @@ -45,4 +170,39 @@ void eventloop::stop() { uv_stop(m_loop.get()); } +uv_loop_t* eventloop::get() const { + return m_loop.get(); +} + +void eventloop::signal_handler(int signum, std::function fun) { + m_sig_handles.emplace_back(std::make_unique(get(), fun)); + m_sig_handles.back()->start(signum); +} + +void eventloop::poll_handler(int events, int fd, std::function fun) { + m_poll_handles.emplace_back(std::make_unique(get(), fd, fun)); + m_poll_handles.back()->start(events); +} + +void eventloop::fs_event_handler(const string& path, std::function fun) { + m_fs_event_handles.emplace_back(std::make_unique(get(), fun)); + m_fs_event_handles.back()->start(path); +} + +void eventloop::pipe_handle(int fd, std::function fun) { + m_pipe_handles.emplace_back(std::make_unique(get(), fun)); + m_pipe_handles.back()->start(fd); +} + +void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, std::function fun) { + m_timer_handles.emplace_back(std::make_unique(get(), fun)); + m_timer_handles.back()->start(timeout, repeat); +} + +AsyncHandle_t eventloop::async_handle(std::function fun) { + m_async_handles.emplace_back(std::make_shared(get(), fun)); + return m_async_handles.back(); +} +// }}} + POLYBAR_NS_END