From e4a608dc63bbebdec30e2d3ae36ee1ccdd9e5691 Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Thu, 5 Jun 2014 19:28:09 +0300 Subject: [PATCH] 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). --- .../xbmc-999.03-0001-handle-SIGTERM.patch | 169 ++++++++++++++++++ .../xbmc-999.03-0001-handle-SIGTERM.patch | 169 ++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 packages/mediacenter/xbmc-master/patches/xbmc-999.03-0001-handle-SIGTERM.patch create mode 100644 packages/mediacenter/xbmc/patches/xbmc-999.03-0001-handle-SIGTERM.patch diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-999.03-0001-handle-SIGTERM.patch b/packages/mediacenter/xbmc-master/patches/xbmc-999.03-0001-handle-SIGTERM.patch new file mode 100644 index 0000000000..6f86040bf5 --- /dev/null +++ b/packages/mediacenter/xbmc-master/patches/xbmc-999.03-0001-handle-SIGTERM.patch @@ -0,0 +1,169 @@ +From dbc86891d089a2a871be5a8663e8a5a9a1cffb53 Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +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 + diff --git a/packages/mediacenter/xbmc/patches/xbmc-999.03-0001-handle-SIGTERM.patch b/packages/mediacenter/xbmc/patches/xbmc-999.03-0001-handle-SIGTERM.patch new file mode 100644 index 0000000000..3b3e5939d4 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-999.03-0001-handle-SIGTERM.patch @@ -0,0 +1,169 @@ +From d3a6ee05721ca6536b30a4e270d1844acfcb0533 Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +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 +