From 8dd2cd41fb4c5a5eb6886cc190419b36084cabfa Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 19 Jan 2025 15:39:19 +0100 Subject: core: move to inotify for monitoring the config files instead of manually polling every second which is not efficient, use inotify. an added bonus is that inotify is much much faster --- src/config/ConfigWatcher.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/config/ConfigWatcher.cpp (limited to 'src/config/ConfigWatcher.cpp') diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp new file mode 100644 index 00000000..38191e9e --- /dev/null +++ b/src/config/ConfigWatcher.cpp @@ -0,0 +1,72 @@ +#include "ConfigWatcher.hpp" +#include +#include "../debug/Log.hpp" +#include +#include + +CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { + if (m_inotifyFd < 0) { + Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); + return; + } + + const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0); + if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) { + Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); + close(m_inotifyFd); + m_inotifyFd = -1; + return; + } +} + +CConfigWatcher::~CConfigWatcher() { + if (m_inotifyFd >= 0) + close(m_inotifyFd); +} + +int CConfigWatcher::getInotifyFD() { + return m_inotifyFd; +} + +void CConfigWatcher::setWatchList(const std::vector& paths) { + + // we clear all watches first, because whichever fired is now invalid + // or that is at least what it seems to be. + // since we don't know which fired, + // plus it doesn't matter that much, these ops are done rarely and fast anyways. + + // cleanup old paths + for (auto& watch : m_watches) { + inotify_rm_watch(m_inotifyFd, watch.wd); + } + + m_watches.clear(); + + // add new paths + for (const auto& path : paths) { + m_watches.emplace_back(SInotifyWatch{ + .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY), + .file = path, + }); + } +} + +void CConfigWatcher::setOnChange(const std::function& fn) { + m_watchCallback = fn; +} + +void CConfigWatcher::onInotifyEvent() { + inotify_event ev; + while (read(m_inotifyFd, &ev, sizeof(ev)) > 0) { + const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); + + if (WD == m_watches.end()) { + Debug::log(ERR, "CConfigWatcher: got an event for wd {} which we don't have?!", ev.wd); + return; + } + + m_watchCallback(SConfigWatchEvent{ + .file = WD->file, + }); + } +} -- cgit v1.2.3