xbmc: handle SIGTERM

In some situations, due to deadlocks or crashes, xbmc fails to exit properly in
CApplication::Stop(), so  g_powerManager.Reboot() / g_powerManager.Powerdown() never gets
called, that's a big no-no for openelec as our users can't shutdown or reboot.
There are few addons reported to cause this behaviour: trakkt.tv, watchdog, weather.underground.

I've also noticed that sometimes new threads (FileCache ??) get started AFTER
CApplication::Stop() is called, delaying shutdown with 1+ minute (2 curl timeoouts?).
The problem seems to be in CJobManager::CancelJobs() but I am too lame to understand where,
why, and how to fix it.

To me, it seems best to let systemd handle it. systemd sends SIGTERM, then waits
TimeoutStopSec=xx seconds then sends SIGKILL,s so dont call g_application.Stop() from
ApplicationMessenger as it can not be trusted. save the requested exitcode instead
(that's required for CEC to switch off the tv) and do it from a simple SIGTERM handler instead.

CEC thread has enough time (5 seconds in xbmc.service) to switch of the TV after receiving OnQuit.
As a side "effect", now guisettings.xml will ALWAYS be saved, even if shutdown / rebooot
is requested externaly (ssh, 3rdparty script).
This commit is contained in:
Stefan Saraev 2014-06-05 19:28:09 +03:00 committed by Stephan Raue
parent fd00ad9503
commit e4a608dc63
2 changed files with 338 additions and 0 deletions

View File

@ -0,0 +1,169 @@
From dbc86891d089a2a871be5a8663e8a5a9a1cffb53 Mon Sep 17 00:00:00 2001
From: Stefan Saraev <stefan@saraev.ca>
Date: Thu, 5 Jun 2014 18:50:04 +0300
Subject: [PATCH] handle SIGTERM
In some situations, due to deadlocks or crashes, xbmc fails to exit properly in
CApplication::Stop(), so g_powerManager.Reboot() / g_powerManager.Powerdown() never gets
called, that's a big no-no for openelec as our users can't shutdown or reboot.
There are few addons reported to cause this behaviour: trakkt.tv, watchdog, weather.underground.
I've also noticed that sometimes new threads (FileCache ??) get started AFTER
CApplication::Stop() is called, delaying shutdown with 1+ minute (2 curl timeoouts?).
The problem seems to be in CJobManager::CancelJobs() but I am too lame to understand where,
why, and how to fix it.
To me, it seems best to let systemd handle it. systemd sends SIGTERM, then waits
TimeoutStopSec=xx seconds then sends SIGKILL,s so dont call g_application.Stop() from
ApplicationMessenger as it can not be trusted. save the requested exitcode instead
(that's required for CEC to switch off the tv) and do it from a simple SIGTERM handler instead.
CEC thread has enough time (5 seconds in xbmc.service) to switch of the TV after receiving OnQuit.
As a side "effect", now guisettings.xml will ALWAYS be saved, even if shutdown / rebooot
is requested externaly (ssh, 3rdparty script).
---
xbmc/Application.cpp | 10 ++++++++--
xbmc/Application.h | 1 +
xbmc/ApplicationMessenger.cpp | 6 ++++--
xbmc/XBApplicationEx.cpp | 1 +
xbmc/XBApplicationEx.h | 1 +
xbmc/main/main.cpp | 15 +++++++++++++++
6 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 7f1b764..4441969 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -3493,11 +3493,18 @@ bool CApplication::Cleanup()
}
}
+void CApplication::SetExitCode(int exitCode)
+{
+ // save it for CEC
+ m_ExitCode = exitCode;
+ m_ExitCodeSet = true;
+}
+
void CApplication::Stop(int exitCode)
{
try
{
- CVariant vExitCode(exitCode);
+ CVariant vExitCode(m_ExitCode);
CAnnouncementManager::Get().Announce(System, "xbmc", "OnQuit", vExitCode);
SaveFileState(true);
@@ -3521,7 +3528,6 @@ void CApplication::Stop(int exitCode)
m_bStop = true;
m_AppFocused = false;
- m_ExitCode = exitCode;
CLog::Log(LOGNOTICE, "stop all");
// cancel any jobs from the jobmanager
diff --git a/xbmc/Application.h b/xbmc/Application.h
index 2243f15..97fb316 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -149,6 +149,7 @@ public:
void StartPVRManager(bool bOpenPVRWindow = false);
void StopPVRManager();
bool IsCurrentThread() const;
+ void SetExitCode(int exitCode);
void Stop(int exitCode);
void RestartApp();
void UnloadSkin(bool forReload = false);
diff --git a/xbmc/ApplicationMessenger.cpp b/xbmc/ApplicationMessenger.cpp
index 3524e89..54a15da 100644
--- a/xbmc/ApplicationMessenger.cpp
+++ b/xbmc/ApplicationMessenger.cpp
@@ -259,13 +259,14 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_POWERDOWN:
{
- g_application.Stop(EXITCODE_POWERDOWN);
+ g_application.SetExitCode(EXITCODE_POWERDOWN);
g_powerManager.Powerdown();
}
break;
case TMSG_QUIT:
{
+ g_application.SetExitCode(EXITCODE_QUIT);
g_application.Stop(EXITCODE_QUIT);
}
break;
@@ -287,7 +288,7 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_RESTART:
case TMSG_RESET:
{
- g_application.Stop(EXITCODE_REBOOT);
+ g_application.SetExitCode(EXITCODE_REBOOT);
g_powerManager.Reboot();
}
break;
@@ -295,6 +296,7 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_RESTARTAPP:
{
#if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
+ g_application.SetExitCode(EXITCODE_RESTARTAPP);
g_application.Stop(EXITCODE_RESTARTAPP);
#endif
}
diff --git a/xbmc/XBApplicationEx.cpp b/xbmc/XBApplicationEx.cpp
index ad6a145..6058938 100644
--- a/xbmc/XBApplicationEx.cpp
+++ b/xbmc/XBApplicationEx.cpp
@@ -40,6 +40,7 @@ CXBApplicationEx::CXBApplicationEx()
m_bStop = false;
m_AppFocused = true;
m_ExitCode = EXITCODE_QUIT;
+ m_ExitCodeSet = false;
m_renderGUI = false;
}
diff --git a/xbmc/XBApplicationEx.h b/xbmc/XBApplicationEx.h
index c46cba1..ed3f35f 100644
--- a/xbmc/XBApplicationEx.h
+++ b/xbmc/XBApplicationEx.h
@@ -40,6 +40,7 @@ public:
// Variables for timing
bool m_bStop;
int m_ExitCode;
+ bool m_ExitCodeSet;
bool m_AppFocused;
bool m_renderGUI;
diff --git a/xbmc/main/main.cpp b/xbmc/main/main.cpp
index ec86426..ad8fe6e 100644
--- a/xbmc/main/main.cpp
+++ b/xbmc/main/main.cpp
@@ -40,9 +40,24 @@
#include "input/linux/LIRC.h"
#endif
#include "XbmcContext.h"
+#include "Application.h"
+
+void xbmc_term_handler(int signum)
+{
+ CLog::Log(LOGINFO, "Received SIGTERM...");
+ if (!g_application.m_ExitCodeSet)
+ g_application.SetExitCode(EXITCODE_RESTARTAPP);
+ g_application.Stop(EXITCODE_RESTARTAPP);
+}
int main(int argc, char* argv[])
{
+ // SIGTERM handler
+ struct sigaction action;
+ memset(&action, 0, sizeof(struct sigaction));
+ action.sa_handler = xbmc_term_handler;
+ sigaction(SIGTERM, &action, NULL);
+
// set up some xbmc specific relationships
XBMC::Context context;
--
1.9.1

View File

@ -0,0 +1,169 @@
From d3a6ee05721ca6536b30a4e270d1844acfcb0533 Mon Sep 17 00:00:00 2001
From: Stefan Saraev <stefan@saraev.ca>
Date: Thu, 5 Jun 2014 18:50:04 +0300
Subject: [PATCH] handle SIGTERM
In some situations, due to deadlocks or crashes, xbmc fails to exit properly in
CApplication::Stop(), so g_powerManager.Reboot() / g_powerManager.Powerdown() never gets
called, that's a big no-no for openelec as our users can't shutdown or reboot.
There are few addons reported to cause this behaviour: trakkt.tv, watchdog, weather.underground.
I've also noticed that sometimes new threads (FileCache ??) get started AFTER
CApplication::Stop() is called, delaying shutdown with 1+ minute (2 curl timeoouts?).
The problem seems to be in CJobManager::CancelJobs() but I am too lame to understand where,
why, and how to fix it.
To me, it seems best to let systemd handle it. systemd sends SIGTERM, then waits
TimeoutStopSec=xx seconds then sends SIGKILL,s so dont call g_application.Stop() from
ApplicationMessenger as it can not be trusted. save the requested exitcode instead
(that's required for CEC to switch off the tv) and do it from a simple SIGTERM handler instead.
CEC thread has enough time (5 seconds in xbmc.service) to switch of the TV after receiving OnQuit.
As a side "effect", now guisettings.xml will ALWAYS be saved, even if shutdown / rebooot
is requested externaly (ssh, 3rdparty script).
---
xbmc/Application.cpp | 10 ++++++++--
xbmc/Application.h | 1 +
xbmc/ApplicationMessenger.cpp | 6 ++++--
xbmc/XBApplicationEx.cpp | 1 +
xbmc/XBApplicationEx.h | 1 +
xbmc/main/main.cpp | 15 +++++++++++++++
6 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 9242d53..1b13667 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -3509,11 +3509,18 @@ bool CApplication::Cleanup()
}
}
+void CApplication::SetExitCode(int exitCode)
+{
+ // save it for CEC
+ m_ExitCode = exitCode;
+ m_ExitCodeSet = true;
+}
+
void CApplication::Stop(int exitCode)
{
try
{
- CVariant vExitCode(exitCode);
+ CVariant vExitCode(m_ExitCode);
CAnnouncementManager::Announce(System, "xbmc", "OnQuit", vExitCode);
SaveFileState(true);
@@ -3537,7 +3544,6 @@ void CApplication::Stop(int exitCode)
m_bStop = true;
m_AppFocused = false;
- m_ExitCode = exitCode;
CLog::Log(LOGNOTICE, "stop all");
// cancel any jobs from the jobmanager
diff --git a/xbmc/Application.h b/xbmc/Application.h
index e3a26c5..35656e3 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -149,6 +149,7 @@ public:
void StartPVRManager(bool bOpenPVRWindow = false);
void StopPVRManager();
bool IsCurrentThread() const;
+ void SetExitCode(int exitCode);
void Stop(int exitCode);
void RestartApp();
void UnloadSkin(bool forReload = false);
diff --git a/xbmc/ApplicationMessenger.cpp b/xbmc/ApplicationMessenger.cpp
index 3524e89..54a15da 100644
--- a/xbmc/ApplicationMessenger.cpp
+++ b/xbmc/ApplicationMessenger.cpp
@@ -259,13 +259,14 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_POWERDOWN:
{
- g_application.Stop(EXITCODE_POWERDOWN);
+ g_application.SetExitCode(EXITCODE_POWERDOWN);
g_powerManager.Powerdown();
}
break;
case TMSG_QUIT:
{
+ g_application.SetExitCode(EXITCODE_QUIT);
g_application.Stop(EXITCODE_QUIT);
}
break;
@@ -287,7 +288,7 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_RESTART:
case TMSG_RESET:
{
- g_application.Stop(EXITCODE_REBOOT);
+ g_application.SetExitCode(EXITCODE_REBOOT);
g_powerManager.Reboot();
}
break;
@@ -295,6 +296,7 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_RESTARTAPP:
{
#if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
+ g_application.SetExitCode(EXITCODE_RESTARTAPP);
g_application.Stop(EXITCODE_RESTARTAPP);
#endif
}
diff --git a/xbmc/XBApplicationEx.cpp b/xbmc/XBApplicationEx.cpp
index ad6a145..6058938 100644
--- a/xbmc/XBApplicationEx.cpp
+++ b/xbmc/XBApplicationEx.cpp
@@ -40,6 +40,7 @@ CXBApplicationEx::CXBApplicationEx()
m_bStop = false;
m_AppFocused = true;
m_ExitCode = EXITCODE_QUIT;
+ m_ExitCodeSet = false;
m_renderGUI = false;
}
diff --git a/xbmc/XBApplicationEx.h b/xbmc/XBApplicationEx.h
index c46cba1..ed3f35f 100644
--- a/xbmc/XBApplicationEx.h
+++ b/xbmc/XBApplicationEx.h
@@ -40,6 +40,7 @@ public:
// Variables for timing
bool m_bStop;
int m_ExitCode;
+ bool m_ExitCodeSet;
bool m_AppFocused;
bool m_renderGUI;
diff --git a/xbmc/main/main.cpp b/xbmc/main/main.cpp
index ec86426..ad8fe6e 100644
--- a/xbmc/main/main.cpp
+++ b/xbmc/main/main.cpp
@@ -40,9 +40,24 @@
#include "input/linux/LIRC.h"
#endif
#include "XbmcContext.h"
+#include "Application.h"
+
+void xbmc_term_handler(int signum)
+{
+ CLog::Log(LOGINFO, "Received SIGTERM...");
+ if (!g_application.m_ExitCodeSet)
+ g_application.SetExitCode(EXITCODE_RESTARTAPP);
+ g_application.Stop(EXITCODE_RESTARTAPP);
+}
int main(int argc, char* argv[])
{
+ // SIGTERM handler
+ struct sigaction action;
+ memset(&action, 0, sizeof(struct sigaction));
+ action.sa_handler = xbmc_term_handler;
+ sigaction(SIGTERM, &action, NULL);
+
// set up some xbmc specific relationships
XBMC::Context context;
--
1.9.1