From 5c1d7401a13cb9beee8d865b1d82610b860a26b9 Mon Sep 17 00:00:00 2001 From: Adrian Muzyka Date: Thu, 11 Jan 2024 14:48:48 +0100 Subject: [PATCH] RDKTV-27601: RDKShell: fix deadlock on gSuspendedOrHibernatedApplicationsMutex --- RDKShell/RDKShell.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/RDKShell/RDKShell.cpp b/RDKShell/RDKShell.cpp index eabf5797aa..93341b947a 100755 --- a/RDKShell/RDKShell.cpp +++ b/RDKShell/RDKShell.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,10 @@ static Device_Mode_FactoryModes_t sFactoryMode = DEVICE_MODE_CVTE_B1_AGING; #ifdef HIBERNATE_SUPPORT_ENABLED std::mutex gSuspendedOrHibernatedApplicationsMutex; map gSuspendedOrHibernatedApplications; + +std::mutex gHibernateBlockedMutex; +int gHibernateBlocked; +std::condition_variable gHibernateBlockedCondVariable; #endif #define ANY_KEY 65536 @@ -250,6 +255,48 @@ enum AppLastExitReason DEACTIVATED }; + +#ifdef HIBERNATE_SUPPORT_ENABLED + +static void setHibernateBlocked(bool val) +{ + std::unique_lock lock(gHibernateBlockedMutex); + if (val) + { + gHibernateBlocked++; + } + else + { + gHibernateBlocked--; + } + std::cout << "setHibernateBlocked("<< gHibernateBlocked <<")" << std::endl; + lock.unlock(); + gHibernateBlockedCondVariable.notify_all(); +} + +static bool waitForHibernateUnblocked(int timeoutMs) +{ + std::unique_lock lock(gHibernateBlockedMutex); + while (gHibernateBlocked > 0) + { + std::cout << "Hibernation blocked, waiting" << std::endl; + if (gHibernateBlockedCondVariable.wait_for(lock, std::chrono::milliseconds(timeoutMs)) + == std::cv_status::timeout) + break; + } + + if (gHibernateBlocked > 0) + { + std::cout << "Hibernation still blocked after " << timeoutMs << "ms !" << std::endl; + return false; + } + + std::cout << "Hibernation not blocked" << std::endl; + return true; +} + +#endif + #ifdef RDKSHELL_READ_MAC_ON_STARTUP static bool checkFactoryMode_wrapper() { @@ -6245,6 +6292,16 @@ namespace WPEFramework { std::thread requestsThread = std::thread([=]() { + if (!waitForHibernateUnblocked(RDKSHELL_THUNDER_TIMEOUT)) + { + std::cout << "Hibernation of " << callsign << " ignored!" << std::endl; + JsonObject eventMsg; + eventMsg["success"] = false; + eventMsg["message"] = "hibernation blocked"; + notify(RDKShell::RDKSHELL_EVENT_ON_HIBERNATED, eventMsg); + return; + } + auto thunderController = RDKShell::getThunderControllerClient(); JsonObject request, result, eventMsg; request["callsign"] = callsign; @@ -6580,6 +6637,17 @@ namespace WPEFramework { skipFocus = gSuspendedOrHibernatedApplications[previousFocusedIterator->first]; } + // If app is not suspended nor hibernated, the hibernation for app can still be triggered + // while waiting in a call to QueryInterfaceByCallsign() or Focused(). Further execution + // of QueryInterfaceByCallsign() or Focused() may cause unwanted wakeup. + // Make sure all new hibernations are blocked untill setting the focuse to false finished + if (skipFocus == false) + { + setHibernateBlocked(true); + } + + gSuspendedOrHibernatedApplicationsMutex.unlock(); + if (skipFocus == false) { #endif @@ -6592,12 +6660,12 @@ namespace WPEFramework { focusedCallsign->Release(); } #ifdef HIBERNATE_SUPPORT_ENABLED + setHibernateBlocked(false); } else { std::cout << "setting the focus for " << compositorName << " to false skipped, plugin suspended or hibernated " << std::endl; } - gSuspendedOrHibernatedApplicationsMutex.unlock(); #endif break; }