/indra/newview/llwatchdog.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 269 lines · 191 code · 40 blank · 38 comment · 15 complexity · 4cae86df3da722949bf385c827c17f50 MD5 · raw file

  1. /**
  2. * @file llthreadwatchdog.cpp
  3. * @brief The LLThreadWatchdog class definitions
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llwatchdog.h"
  28. const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000;
  29. void default_killer_callback()
  30. {
  31. #ifdef LL_WINDOWS
  32. RaiseException(0,0,0,0);
  33. #else
  34. raise(SIGQUIT);
  35. #endif
  36. }
  37. // This class runs the watchdog timing thread.
  38. class LLWatchdogTimerThread : public LLThread
  39. {
  40. public:
  41. LLWatchdogTimerThread() :
  42. LLThread("Watchdog"),
  43. mSleepMsecs(0),
  44. mStopping(false)
  45. {
  46. }
  47. ~LLWatchdogTimerThread() {}
  48. void setSleepTime(long ms) { mSleepMsecs = ms; }
  49. void stop()
  50. {
  51. mStopping = true;
  52. mSleepMsecs = 1;
  53. }
  54. /* virtual */ void run()
  55. {
  56. while(!mStopping)
  57. {
  58. LLWatchdog::getInstance()->run();
  59. ms_sleep(mSleepMsecs);
  60. }
  61. }
  62. private:
  63. long mSleepMsecs;
  64. bool mStopping;
  65. };
  66. // LLWatchdogEntry
  67. LLWatchdogEntry::LLWatchdogEntry()
  68. {
  69. }
  70. LLWatchdogEntry::~LLWatchdogEntry()
  71. {
  72. stop();
  73. }
  74. void LLWatchdogEntry::start()
  75. {
  76. LLWatchdog::getInstance()->add(this);
  77. }
  78. void LLWatchdogEntry::stop()
  79. {
  80. LLWatchdog::getInstance()->remove(this);
  81. }
  82. // LLWatchdogTimeout
  83. const std::string UNINIT_STRING = "uninitialized";
  84. LLWatchdogTimeout::LLWatchdogTimeout() :
  85. mTimeout(0.0f),
  86. mPingState(UNINIT_STRING)
  87. {
  88. }
  89. LLWatchdogTimeout::~LLWatchdogTimeout()
  90. {
  91. }
  92. bool LLWatchdogTimeout::isAlive() const
  93. {
  94. return (mTimer.getStarted() && !mTimer.hasExpired());
  95. }
  96. void LLWatchdogTimeout::reset()
  97. {
  98. mTimer.setTimerExpirySec(mTimeout);
  99. }
  100. void LLWatchdogTimeout::setTimeout(F32 d)
  101. {
  102. mTimeout = d;
  103. }
  104. void LLWatchdogTimeout::start(const std::string& state)
  105. {
  106. // Order of operation is very impmortant here.
  107. // After LLWatchdogEntry::start() is called
  108. // LLWatchdogTimeout::isAlive() will be called asynchronously.
  109. ping(state);
  110. mTimer.start();
  111. LLWatchdogEntry::start();
  112. }
  113. void LLWatchdogTimeout::stop()
  114. {
  115. LLWatchdogEntry::stop();
  116. mTimer.stop();
  117. }
  118. void LLWatchdogTimeout::ping(const std::string& state)
  119. {
  120. if(!state.empty())
  121. {
  122. mPingState = state;
  123. }
  124. reset();
  125. }
  126. // LLWatchdog
  127. LLWatchdog::LLWatchdog() :
  128. mSuspectsAccessMutex(NULL),
  129. mTimer(NULL),
  130. mLastClockCount(0),
  131. mKillerCallback(&default_killer_callback)
  132. {
  133. }
  134. LLWatchdog::~LLWatchdog()
  135. {
  136. }
  137. void LLWatchdog::add(LLWatchdogEntry* e)
  138. {
  139. lockThread();
  140. mSuspects.insert(e);
  141. unlockThread();
  142. }
  143. void LLWatchdog::remove(LLWatchdogEntry* e)
  144. {
  145. lockThread();
  146. mSuspects.erase(e);
  147. unlockThread();
  148. }
  149. void LLWatchdog::init(killer_event_callback func)
  150. {
  151. mKillerCallback = func;
  152. if(!mSuspectsAccessMutex && !mTimer)
  153. {
  154. mSuspectsAccessMutex = new LLMutex(NULL);
  155. mTimer = new LLWatchdogTimerThread();
  156. mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000);
  157. mLastClockCount = LLTimer::getTotalTime();
  158. // mTimer->start() kicks off the thread, any code after
  159. // start needs to use the mSuspectsAccessMutex
  160. mTimer->start();
  161. }
  162. }
  163. void LLWatchdog::cleanup()
  164. {
  165. if(mTimer)
  166. {
  167. mTimer->stop();
  168. delete mTimer;
  169. mTimer = NULL;
  170. }
  171. if(mSuspectsAccessMutex)
  172. {
  173. delete mSuspectsAccessMutex;
  174. mSuspectsAccessMutex = NULL;
  175. }
  176. mLastClockCount = 0;
  177. }
  178. void LLWatchdog::run()
  179. {
  180. lockThread();
  181. // Check the time since the last call to run...
  182. // If the time elapsed is two times greater than the regualr sleep time
  183. // reset the active timeouts.
  184. const U32 TIME_ELAPSED_MULTIPLIER = 2;
  185. U64 current_time = LLTimer::getTotalTime();
  186. U64 current_run_delta = current_time - mLastClockCount;
  187. mLastClockCount = current_time;
  188. if(current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER))
  189. {
  190. llinfos << "Watchdog thread delayed: resetting entries." << llendl;
  191. std::for_each(mSuspects.begin(),
  192. mSuspects.end(),
  193. std::mem_fun(&LLWatchdogEntry::reset)
  194. );
  195. }
  196. else
  197. {
  198. SuspectsRegistry::iterator result =
  199. std::find_if(mSuspects.begin(),
  200. mSuspects.end(),
  201. std::not1(std::mem_fun(&LLWatchdogEntry::isAlive))
  202. );
  203. if(result != mSuspects.end())
  204. {
  205. // error!!!
  206. if(mTimer)
  207. {
  208. mTimer->stop();
  209. }
  210. llinfos << "Watchdog detected error:" << llendl;
  211. mKillerCallback();
  212. }
  213. }
  214. unlockThread();
  215. }
  216. void LLWatchdog::lockThread()
  217. {
  218. if(mSuspectsAccessMutex != NULL)
  219. {
  220. mSuspectsAccessMutex->lock();
  221. }
  222. }
  223. void LLWatchdog::unlockThread()
  224. {
  225. if(mSuspectsAccessMutex != NULL)
  226. {
  227. mSuspectsAccessMutex->unlock();
  228. }
  229. }