Util_Watchdog.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /************************************************************************************
  2. Filename : Util_Watchdog.cpp
  3. Content : Deadlock reaction
  4. Created : June 27, 2013
  5. Authors : Kevin Jenkins, Chris Taylor
  6. Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
  7. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
  8. you may not use the Oculus VR Rift SDK except in compliance with the License,
  9. which is provided at the time of installation or download, or which
  10. otherwise accompanies this software in either electronic or hard copy form.
  11. You may obtain a copy of the License at
  12. http://www.oculusvr.com/licenses/LICENSE-3.2
  13. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  14. distributed under the License is distributed on an "AS IS" BASIS,
  15. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. See the License for the specific language governing permissions and
  17. limitations under the License.
  18. *************************************************************************************/
  19. #include "Util_Watchdog.h"
  20. #include "Kernel/OVR_DebugHelp.h"
  21. #include "Kernel/OVR_Win32_IncludeWindows.h"
  22. #if defined(OVR_OS_LINUX) || defined(OVR_OS_MAC)
  23. #include <unistd.h>
  24. #include <sys/types.h>
  25. #include <sys/ptrace.h>
  26. #if defined(OVR_OS_LINUX)
  27. #include <sys/wait.h>
  28. #endif
  29. #endif
  30. OVR_DEFINE_SINGLETON(OVR::Util::WatchDogObserver);
  31. namespace OVR { namespace Util {
  32. const int DefaultThreshhold = 60000; // milliseconds
  33. //-----------------------------------------------------------------------------
  34. // Tools
  35. static uint32_t GetFastMsTime()
  36. {
  37. #if defined(OVR_OS_MS)
  38. return ::GetTickCount();
  39. #else
  40. return Timer::GetTicksMs();
  41. #endif
  42. }
  43. //-----------------------------------------------------------------------------
  44. // WatchDogObserver
  45. static bool ExitingOnDeadlock = false;
  46. bool WatchDogObserver::IsExitingOnDeadlock()
  47. {
  48. return ExitingOnDeadlock;
  49. }
  50. void WatchDogObserver::SetExitingOnDeadlock(bool enabled)
  51. {
  52. ExitingOnDeadlock = enabled;
  53. }
  54. WatchDogObserver::WatchDogObserver() :
  55. IsReporting(false)
  56. {
  57. Start();
  58. // Must be at end of function
  59. PushDestroyCallbacks();
  60. }
  61. WatchDogObserver::~WatchDogObserver()
  62. {
  63. TerminationEvent.SetEvent();
  64. Join();
  65. }
  66. void WatchDogObserver::OnThreadDestroy()
  67. {
  68. TerminationEvent.SetEvent();
  69. }
  70. void WatchDogObserver::OnSystemDestroy()
  71. {
  72. Release();
  73. }
  74. int WatchDogObserver::Run()
  75. {
  76. OVR_DEBUG_LOG(("[WatchDogObserver] Starting"));
  77. SetThreadName("WatchDog");
  78. while (!TerminationEvent.Wait(WakeupInterval))
  79. {
  80. Lock::Locker locker(&ListLock);
  81. const uint32_t t1 = GetFastMsTime();
  82. const int count = DogList.GetSizeI();
  83. for (int i = 0; i < count; ++i)
  84. {
  85. WatchDog* dog = DogList[i];
  86. const int threshold = dog->ThreshholdMilliseconds;
  87. const uint32_t t0 = dog->WhenLastFedMilliseconds;
  88. // If threshold exceeded, assume there is thread deadlock of some sort.
  89. int delta = (int)(t1 - t0);
  90. if (delta > threshold)
  91. {
  92. // Expected behavior:
  93. // SingleProcessDebug, SingleProcessRelease, Debug: This is only ever done for internal testing, so we don't want it to trigger the deadlock termination.
  94. // Release: This is our release configuration where we want it to terminate itself.
  95. // Print a stack trace of all threads if there's no debugger present.
  96. const bool debuggerPresent = OVRIsDebuggerPresent();
  97. LogError("{ERR-027} [WatchDogObserver] Deadlock detected: %s", dog->ThreadName.ToCStr());
  98. if (!debuggerPresent) // We don't print threads if a debugger is present because otherwise every time the developer paused the app to debug, it would spit out a long thread trace upon resuming.
  99. {
  100. if (SymbolLookup::Initialize())
  101. {
  102. // symbolLookup is static here to avoid putting 32 KB on the stack
  103. // and potentially overflowing the stack. This function is only ever
  104. // run by one thread so it should be safe.
  105. static SymbolLookup symbolLookup;
  106. String threadListOutput, moduleListOutput;
  107. symbolLookup.ReportThreadCallstacks(threadListOutput);
  108. symbolLookup.ReportModuleInformation(moduleListOutput);
  109. LogError("---DEADLOCK STATE---\n\n%s\n\n%s\n---END OF DEADLOCK STATE---", threadListOutput.ToCStr(), moduleListOutput.ToCStr());
  110. }
  111. if (IsReporting)
  112. {
  113. ExceptionHandler::ReportDeadlock(DogList[i]->ThreadName, OrganizationName , ApplicationName);
  114. // Disable reporting after the first deadlock report.
  115. IsReporting = false;
  116. }
  117. }
  118. if (IsExitingOnDeadlock())
  119. {
  120. OVR_ASSERT_M(false, "Watchdog detected a deadlock. Exiting the process."); // This won't have an effect unless asserts are enabled in release builds.
  121. OVR::ExitProcess(-1);
  122. }
  123. }
  124. }
  125. }
  126. OVR_DEBUG_LOG(("[WatchDogObserver] Good night"));
  127. return 0;
  128. }
  129. void WatchDogObserver::Add(WatchDog *dog)
  130. {
  131. Lock::Locker locker(&ListLock);
  132. if (!dog->Listed)
  133. {
  134. DogList.PushBack(dog);
  135. dog->Listed = true;
  136. }
  137. }
  138. void WatchDogObserver::Remove(WatchDog *dog)
  139. {
  140. Lock::Locker locker(&ListLock);
  141. if (dog->Listed)
  142. {
  143. for (int i = 0; i < DogList.GetSizeI(); ++i)
  144. {
  145. if (DogList[i] == dog)
  146. {
  147. DogList.RemoveAt(i--);
  148. }
  149. }
  150. dog->Listed = false;
  151. }
  152. }
  153. void WatchDogObserver::EnableReporting(const String organization, const String application)
  154. {
  155. OrganizationName = organization;
  156. ApplicationName = application;
  157. IsReporting = true;
  158. }
  159. void WatchDogObserver::DisableReporting()
  160. {
  161. IsReporting = false;
  162. }
  163. //-----------------------------------------------------------------------------
  164. // WatchDog
  165. WatchDog::WatchDog(const String& threadName) :
  166. ThreshholdMilliseconds(DefaultThreshhold),
  167. ThreadName(threadName),
  168. Listed(false)
  169. {
  170. WhenLastFedMilliseconds = GetFastMsTime();
  171. }
  172. WatchDog::~WatchDog()
  173. {
  174. Disable();
  175. }
  176. void WatchDog::Disable()
  177. {
  178. WatchDogObserver::GetInstance()->Remove(this);
  179. }
  180. void WatchDog::Enable()
  181. {
  182. WatchDogObserver::GetInstance()->Add(this);
  183. }
  184. void WatchDog::Feed(int threshold)
  185. {
  186. WhenLastFedMilliseconds = GetFastMsTime();
  187. ThreshholdMilliseconds = threshold;
  188. if (!Listed)
  189. {
  190. Enable();
  191. }
  192. }
  193. }} // namespace OVR::Util