Skip to content

Commit

Permalink
RDKTV-27601: RDKShell: fix deadlock on gSuspendedOrHibernatedApplicat…
Browse files Browse the repository at this point in the history
…ionsMutex
  • Loading branch information
adrianM27 committed Feb 22, 2024
1 parent e71a480 commit a69ab53
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
4 changes: 4 additions & 0 deletions RDKShell/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ All notable changes to this RDK Service will be documented in this file.
* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development.

* For more details, refer to [versioning](https://github.com/rdkcentral/rdkservices#versioning) section under Main README.
## [1.4.14] - 2024-02-22
### Fixed
- Fix RDKShell deadlock on gSuspendedOrHibernatedApplicationMutex

## [1.4.13] - 2024-02-06
### Fixed
- Fixed coverity reported issues
Expand Down
72 changes: 70 additions & 2 deletions RDKShell/RDKShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <thread>
#include <fstream>
#include <sstream>
#include <condition_variable>
#include <unistd.h>
#include <rdkshell/compositorcontroller.h>
#include <rdkshell/application.h>
Expand Down Expand Up @@ -52,7 +53,7 @@

#define API_VERSION_NUMBER_MAJOR 1
#define API_VERSION_NUMBER_MINOR 4
#define API_VERSION_NUMBER_PATCH 13
#define API_VERSION_NUMBER_PATCH 14

const string WPEFramework::Plugin::RDKShell::SERVICE_NAME = "org.rdk.RDKShell";
//methods
Expand Down Expand Up @@ -204,6 +205,10 @@ static Device_Mode_FactoryModes_t sFactoryMode = DEVICE_MODE_CVTE_B1_AGING;
#ifdef HIBERNATE_SUPPORT_ENABLED
std::mutex gSuspendedOrHibernatedApplicationsMutex;
map<string, bool> gSuspendedOrHibernatedApplications;

std::mutex gHibernateBlockedMutex;
int gHibernateBlocked;
std::condition_variable gHibernateBlockedCondVariable;
#endif

#define ANY_KEY 65536
Expand Down Expand Up @@ -250,6 +255,48 @@ enum AppLastExitReason
DEACTIVATED
};


#ifdef HIBERNATE_SUPPORT_ENABLED

static void setHibernateBlocked(bool val)
{
std::unique_lock<std::mutex> 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<std::mutex> 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()
{
Expand Down Expand Up @@ -6253,6 +6300,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;
Expand Down Expand Up @@ -6588,6 +6645,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
Expand All @@ -6600,12 +6668,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;
}
Expand Down

0 comments on commit a69ab53

Please sign in to comment.