From 6fc09324ab4ead2b8896f9f2cf1fbb1bce75e2d5 Mon Sep 17 00:00:00 2001 From: scorpion-26 Date: Fri, 15 Mar 2024 19:30:38 +0100 Subject: [PATCH] Only allow sequential runs of package checking If the current monitor would quickly change, GetOutdatedPackagesAsync would be called while the previous instance is still running, which caused crashes. Now, GetOutdatedPackagesAsync only uses one instance/callback a time. --- src/System.cpp | 64 +++++++++++++++++++++++++++++--------------------- src/System.h | 1 + 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/System.cpp b/src/System.cpp index c627840..d041bfb 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -576,17 +576,28 @@ namespace System void GetOutdatedPackagesAsync(std::function&& returnVal) { + static bool currentlyRunning = false; + static std::function handlerFunction; static std::mutex configMutex; - configMutex.lock(); - if (!RuntimeConfig::Get().hasPackagesScript) + { - configMutex.unlock(); - return; // Don't bother + std::scoped_lock lock(configMutex); + if (!RuntimeConfig::Get().hasPackagesScript) + { + return; // Don't bother + } + handlerFunction = returnVal; + if (currentlyRunning) + { + // Thread is running, only update handler + return; + } + + currentlyRunning = true; } - configMutex.unlock(); std::thread( - [](std::function returnVal) + [&]() { // We need a pipe, since there is no "libpacman". This should only be called every so often anyways std::string number; @@ -601,29 +612,28 @@ namespace System ASSERT(feof(pipe), "GetOutdatedPackages: Cannot read to eof!"); int exitCode = pclose(pipe) / 256; - if (exitCode != 0) { - configMutex.lock(); - // Invalid script/error - LOG("GetOutdatedPackages: Invalid command. Disabling package widget!"); - RuntimeConfig::Get().hasPackagesScript = false; - configMutex.unlock(); - return; + std::scoped_lock lock(configMutex); + if (exitCode != 0) + { + // Invalid script/error + LOG("GetOutdatedPackages: Invalid command. Disabling package widget!"); + RuntimeConfig::Get().hasPackagesScript = false; + currentlyRunning = false; + return; + } + try + { + handlerFunction(std::stoul(buf)); + } + catch (std::invalid_argument&) + { + LOG("GetOutdatedPackages: Invalid output of the package script. Disabling package widget!"); + RuntimeConfig::Get().hasPackagesScript = false; + } + currentlyRunning = false; } - try - { - returnVal(std::stoul(buf)); - } - catch (std::invalid_argument&) - { - configMutex.lock(); - LOG("GetOutdatedPackages: Invalid output of the package script. Disabling package widget!"); - RuntimeConfig::Get().hasPackagesScript = false; - configMutex.unlock(); - return; - } - }, - std::move(returnVal)) + }) .detach(); } diff --git a/src/System.h b/src/System.h index 89f6b64..e078198 100644 --- a/src/System.h +++ b/src/System.h @@ -108,6 +108,7 @@ namespace System // Bytes per second download. dx is time since last call. Will always return 0 on first run double GetNetworkBpsDownload(double dt); + // This can only be called one at a time. If it is already running it is assumed, that the old handler is no longer valid. void GetOutdatedPackagesAsync(std::function&& returnVal); std::string GetTime();