From 9d9fe8bffbd177d4fee7750fbd93a62fbbbfca0b Mon Sep 17 00:00:00 2001 From: patrick96 Date: Sat, 11 Sep 2021 11:46:37 +0200 Subject: [PATCH] Better error handling --- include/components/controller.hpp | 2 ++ include/components/eventloop.hpp | 15 +++++---- include/events/types.hpp | 7 ++++ src/components/controller.cpp | 55 ++++++++++++++++++++----------- src/ipc.cpp | 2 +- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/include/components/controller.hpp b/include/components/controller.hpp index ad834a6b..4bedacdf 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -53,6 +53,8 @@ class controller bool enqueue(event&& evt); bool enqueue(string&& input_data); + void stop(bool reload); + void signal_handler(int signum); void conn_cb(int status, int events); diff --git a/include/components/eventloop.hpp b/include/components/eventloop.hpp index 32c993fc..1bd92d49 100644 --- a/include/components/eventloop.hpp +++ b/include/components/eventloop.hpp @@ -5,6 +5,7 @@ #include #include "common.hpp" +#include "components/logger.hpp" POLYBAR_NS @@ -12,11 +13,13 @@ POLYBAR_NS * Runs any libuv function with an integer error code return value and throws an * exception on error. */ -#define UV(fun, ...) \ - int res = fun(__VA_ARGS__); \ - if (res < 0) { \ - throw std::runtime_error("libuv error for '" #fun "': "s + uv_strerror(res)); \ - } +#define UV(fun, ...) \ + do { \ + int res = fun(__VA_ARGS__); \ + if (res < 0) { \ + throw std::runtime_error("libuv error for '" #fun "': "s + uv_strerror(res)); \ + } \ + } while (0); template struct cb_helper { @@ -51,7 +54,7 @@ struct SignalHandle : public UVHandle { }; struct PollHandle : public UVHandle { - // TODO wrap callback and handle negative status + // 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); } diff --git a/include/events/types.hpp b/include/events/types.hpp index 22e4fe14..34a3d965 100644 --- a/include/events/types.hpp +++ b/include/events/types.hpp @@ -27,6 +27,13 @@ namespace { return !(id == static_cast(type)); } + /** + * Create QUIT event + */ + inline event make_none_evt() { + return event{static_cast(event_type::NONE)}; + } + /** * Create QUIT event */ diff --git a/src/components/controller.cpp b/src/components/controller.cpp index 56b36a88..e5a722a0 100644 --- a/src/components/controller.cpp +++ b/src/components/controller.cpp @@ -134,6 +134,7 @@ bool controller::run(bool writeback, string snapshot_dst) { read_events(); if (m_event_thread.joinable()) { + m_log.info("Joining event thread"); m_event_thread.join(); } @@ -153,9 +154,6 @@ bool controller::enqueue(event&& evt) { m_log.warn("Failed to enqueue event"); return false; } - // if (write(g_eventpipe[PIPE_WRITE], " ", 1) == -1) { - // m_log.err("Failed to write to eventpipe (reason: %s)", strerror(errno)); - // } return true; } @@ -172,17 +170,28 @@ bool controller::enqueue(string&& input_data) { return false; } -void controller::conn_cb(int, int) { - // TODO handle negative status - if (m_connection.connection_has_error()) { - g_terminate = 1; - g_reload = 0; - eloop->stop(); +void controller::stop(bool reload) { + g_terminate = 1; + g_reload = reload; + eloop->stop(); +} + +void controller::conn_cb(int status, int) { + if (status < 0) { + // TODO Should we stop polling here? + m_log.err("libuv error while polling X connection: %s", uv_strerror(status)); + return; + } + + int xcb_error = m_connection.connection_has_error(); + if ((xcb_error = m_connection.connection_has_error()) > 0) { + m_log.err("X connection error, terminating... (what: %s)", m_connection.error_str(xcb_error)); + stop(false); return; } shared_ptr evt{}; - while ((evt = shared_ptr(xcb_poll_for_event(m_connection), free)) != nullptr) { + if ((evt = shared_ptr(xcb_poll_for_event(m_connection), free)) != nullptr) { try { m_connection.dispatch_event(evt); } catch (xpp::connection_error& err) { @@ -190,6 +199,12 @@ void controller::conn_cb(int, int) { } catch (const exception& err) { m_log.err("Error in X event loop: %s", err.what()); } + } else { + if ((xcb_error = m_connection.connection_has_error()) > 0) { + m_log.err("X connection error, terminating... (what: %s)", m_connection.error_str(xcb_error)); + stop(false); + return; + } } } @@ -200,19 +215,15 @@ void controller::ipc_cb(string buf) { void controller::signal_handler(int signum) { m_log.notice("Received signal SIG%s", sigabbrev_np(signum)); - g_terminate = 1; - g_reload = (signum == SIGUSR1); - eloop->stop(); + stop(signum == SIGUSR1); } -void controller::confwatch_handler(const char*, int, int) { - g_terminate = 1; - g_reload = 1; - eloop->stop(); +void controller::confwatch_handler(const char* filename, int, int) { + m_log.notice("Watched config file changed %s", filename); + stop(true); } static void ipc_alloc_cb(uv_handle_t*, size_t, uv_buf_t* buf) { - // TODO handle alloc error buf->base = new char[BUFSIZ]; buf->len = BUFSIZ; } @@ -271,10 +282,14 @@ void controller::read_events() { eloop->run(); } catch (const exception& err) { m_log.err("Fatal Error in eventloop: %s", err.what()); - g_terminate = 1; - eloop->stop(); + stop(false); } + // Notify event queue so that it stops + enqueue(make_none_evt()); + + m_log.info("Eventloop finished"); + eloop.reset(); } diff --git a/src/ipc.cpp b/src/ipc.cpp index 49c61b1e..333d4952 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -116,7 +116,7 @@ int main(int argc, char** argv) { // against pid if one was defined for (auto&& channel : pipes) { try { - file_descriptor fd(channel, O_WRONLY | O_NONBLOCK); + file_descriptor fd(channel, O_WRONLY | O_NONBLOCK, true); string payload{ipc_type + ':' + ipc_payload}; if (write(fd, payload.c_str(), payload.size()) != -1) { display("Successfully wrote \"" + payload + "\" to \"" + channel + "\"");