aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorvaxerski <[email protected]>2023-09-29 16:38:13 +0100
committervaxerski <[email protected]>2023-09-29 16:38:13 +0100
commit9cc614d096db4b7c1de6baaa055ca6f741aa4370 (patch)
tree23e6c59fed8dea0c27669bd9a4dec6a31e54aa8b
parent3f09b14381e8b28dd2cc1d292763374f2d6c8484 (diff)
downloadHyprland-9cc614d096db4b7c1de6baaa055ca6f741aa4370.tar.gz
Hyprland-9cc614d096db4b7c1de6baaa055ca6f741aa4370.zip
internal: add a watchdog
a watchdog will abort processing a signal if a timeout specified via debug:watchdog_timeout is reached.
-rw-r--r--src/Compositor.cpp11
-rw-r--r--src/Compositor.hpp1
-rw-r--r--src/config/ConfigManager.cpp1
-rw-r--r--src/helpers/WLListener.cpp8
-rw-r--r--src/helpers/Watchdog.cpp49
-rw-r--r--src/helpers/Watchdog.hpp30
6 files changed, 99 insertions, 1 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 1cb378db..e114e934 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -34,6 +34,13 @@ void handleUnrecoverableSignal(int sig) {
abort();
}
+void handleUserSignal(int sig) {
+ if (sig == SIGUSR1) {
+ // means we have to unwind a timed out event
+ throw std::exception();
+ }
+}
+
CCompositor::CCompositor() {
m_iHyprlandPID = getpid();
@@ -70,6 +77,8 @@ CCompositor::CCompositor() {
setRandomSplash();
Debug::log(LOG, "\nCurrent splash: {}\n\n", m_szCurrentSplash);
+
+ g_pWatchdog = std::make_unique<CWatchdog>();
}
CCompositor::~CCompositor() {
@@ -92,6 +101,7 @@ CCompositor::~CCompositor() {
g_pAnimationManager.reset();
g_pKeybindManager.reset();
g_pHookSystem.reset();
+ g_pWatchdog.reset();
}
void CCompositor::setRandomSplash() {
@@ -112,6 +122,7 @@ void CCompositor::initServer() {
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
signal(SIGSEGV, handleUnrecoverableSignal);
signal(SIGABRT, handleUnrecoverableSignal);
+ signal(SIGUSR1, handleUserSignal);
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr);
initManagers(STAGE_PRIORITY);
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index 99839b06..86460211 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -27,6 +27,7 @@
#include "render/OpenGL.hpp"
#include "hyprerror/HyprError.hpp"
#include "plugins/PluginSystem.hpp"
+#include "helpers/Watchdog.hpp"
enum eManagersInitStage
{
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index fc7a9e3e..9f696aca 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -134,6 +134,7 @@ void CConfigManager::setDefaultVars() {
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
configValues["debug:manual_crash"].intValue = 0;
configValues["debug:suppress_errors"].intValue = 0;
+ configValues["debug:watchdog_timeout"].intValue = 5;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur:enabled"].intValue = 1;
diff --git a/src/helpers/WLListener.cpp b/src/helpers/WLListener.cpp
index 3cb051b7..cace665d 100644
--- a/src/helpers/WLListener.cpp
+++ b/src/helpers/WLListener.cpp
@@ -6,7 +6,13 @@
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
- pWrap->m_pSelf->emit(data);
+ g_pWatchdog->startWatching();
+
+ try {
+ pWrap->m_pSelf->emit(data);
+ } catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
+
+ g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
diff --git a/src/helpers/Watchdog.cpp b/src/helpers/Watchdog.cpp
new file mode 100644
index 00000000..92f20dfb
--- /dev/null
+++ b/src/helpers/Watchdog.cpp
@@ -0,0 +1,49 @@
+#include "Watchdog.hpp"
+#include <signal.h>
+#include "config/ConfigManager.hpp"
+
+CWatchdog::CWatchdog() {
+ m_iMainThreadPID = pthread_self();
+
+ m_pWatchdog = std::make_unique<std::thread>([this] {
+ static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
+
+ while (1337) {
+ std::unique_lock lk(m_mWatchdogMutex);
+
+ if (!m_bWillWatch)
+ m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; });
+ else {
+ if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
+ pthread_kill(m_iMainThreadPID, SIGUSR1);
+ }
+
+ m_bWatching = false;
+ m_bNotified = false;
+ }
+ });
+
+ m_pWatchdog->detach();
+}
+
+void CWatchdog::startWatching() {
+ static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
+
+ if (*PTIMEOUT == 0)
+ return;
+
+ m_tTriggered = std::chrono::high_resolution_clock::now();
+ m_bWillWatch = true;
+ m_bWatching = true;
+
+ m_bNotified = true;
+ m_cvWatchdogCondition.notify_all();
+}
+
+void CWatchdog::endWatching() {
+ m_bWatching = false;
+ m_bWillWatch = false;
+
+ m_bNotified = true;
+ m_cvWatchdogCondition.notify_all();
+} \ No newline at end of file
diff --git a/src/helpers/Watchdog.hpp b/src/helpers/Watchdog.hpp
new file mode 100644
index 00000000..1868bd0f
--- /dev/null
+++ b/src/helpers/Watchdog.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <memory>
+#include <chrono>
+#include <thread>
+#include <condition_variable>
+
+class CWatchdog {
+ public:
+ // must be called from the main thread
+ CWatchdog();
+
+ void startWatching();
+ void endWatching();
+
+ private:
+ std::chrono::high_resolution_clock::time_point m_tTriggered;
+
+ pthread_t m_iMainThreadPID = 0;
+
+ bool m_bWatching = false;
+ bool m_bWillWatch = false;
+
+ std::unique_ptr<std::thread> m_pWatchdog;
+ std::mutex m_mWatchdogMutex;
+ bool m_bNotified = false;
+ std::condition_variable m_cvWatchdogCondition;
+};
+
+inline std::unique_ptr<CWatchdog> g_pWatchdog; \ No newline at end of file