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 + "\"");