29 using System.Collections.Generic;
31 using System.Threading;
34 namespace OpenSim.Framework.Monitoring
39 public static class Watchdog
41 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44 public const double WATCHDOG_INTERVAL_MS = 2500.0d;
47 public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000;
49 [System.Diagnostics.DebuggerDisplay(
"{Thread.Name}")]
60 public int FirstTick {
get;
private set; }
65 public int LastTick {
get; set; }
70 public int Timeout {
get; set; }
75 public bool IsTimedOut {
get; set; }
80 public bool AlarmIfTimeout {
get; set; }
85 public Func<string> AlarmMethod {
get; set; }
96 FirstTick = Environment.TickCount & Int32.MaxValue;
102 string.Format(
"Last update of thread {0}", name),
109 stat => stat.Value = Environment.TickCount & Int32.MaxValue - LastTick,
112 StatsManager.RegisterStat(
Stat);
117 Thread = previousTwi.Thread;
118 FirstTick = previousTwi.FirstTick;
119 LastTick = previousTwi.LastTick;
120 Timeout = previousTwi.Timeout;
121 IsTimedOut = previousTwi.IsTimedOut;
122 AlarmIfTimeout = previousTwi.AlarmIfTimeout;
123 AlarmMethod = previousTwi.AlarmMethod;
128 StatsManager.DeregisterStat(
Stat);
136 public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
141 public static bool Enabled
143 get {
return m_enabled; }
148 if (value == m_enabled)
156 LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
159 m_watchdogTimer.Enabled = m_enabled;
163 private static bool m_enabled;
164 private static Dictionary<int, ThreadWatchdogInfo> m_threads;
165 private static System.Timers.Timer m_watchdogTimer;
173 public static int LastWatchdogThreadTick {
get;
private set; }
177 m_threads =
new Dictionary<int, ThreadWatchdogInfo>();
178 m_watchdogTimer =
new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
179 m_watchdogTimer.AutoReset =
false;
180 m_watchdogTimer.Elapsed += WatchdogTimerElapsed;
189 public static void AddThread(ThreadWatchdogInfo info,
string name,
bool log =
true)
193 "[WATCHDOG]: Started tracking thread {0}, ID {1}", name, info.Thread.ManagedThreadId);
196 m_threads.Add(info.Thread.ManagedThreadId, info);
202 public static
void UpdateThread()
204 UpdateThread(
Thread.CurrentThread.ManagedThreadId);
215 public static bool RemoveThread(
bool log =
true)
217 return RemoveThread(
Thread.CurrentThread.ManagedThreadId, log);
220 private static bool RemoveThread(
int threadID,
bool log =
true)
224 ThreadWatchdogInfo twi;
225 if (m_threads.TryGetValue(threadID, out twi))
229 "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
232 m_threads.Remove(threadID);
239 "[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
246 public static bool AbortThread(
int threadID)
250 if (m_threads.ContainsKey(threadID))
252 ThreadWatchdogInfo twi = m_threads[threadID];
254 RemoveThread(threadID);
265 private static void UpdateThread(
int threadID)
267 ThreadWatchdogInfo threadInfo;
275 if (m_threads.TryGetValue(threadID, out threadInfo))
277 threadInfo.LastTick = Environment.TickCount & Int32.MaxValue;
278 threadInfo.IsTimedOut =
false;
282 m_log.WarnFormat(
"[WATCHDOG]: Asked to update thread {0} which is not being monitored", threadID);
292 public static ThreadWatchdogInfo[] GetThreadsInfo()
295 return m_threads.Values.ToArray();
302 public static ThreadWatchdogInfo GetCurrentThreadInfo()
306 if (m_threads.ContainsKey(
Thread.CurrentThread.ManagedThreadId))
307 return m_threads[
Thread.CurrentThread.ManagedThreadId];
318 private static void WatchdogTimerElapsed(
object sender, System.Timers.ElapsedEventArgs e)
320 int now = Environment.TickCount & Int32.MaxValue;
321 int msElapsed = now - LastWatchdogThreadTick;
323 if (msElapsed > WATCHDOG_INTERVAL_MS * 2)
325 "[WATCHDOG]: {0} ms since Watchdog last ran. Interval should be approximately {1} ms",
326 msElapsed, WATCHDOG_INTERVAL_MS);
328 LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
330 Action<ThreadWatchdogInfo> callback = OnWatchdogTimeout;
332 if (callback != null)
334 List<ThreadWatchdogInfo> callbackInfos = null;
335 List<ThreadWatchdogInfo> threadsInfo;
340 threadsInfo = m_threads.Values.ToList();
342 foreach(ThreadWatchdogInfo threadInfo
in threadsInfo)
344 if(threadInfo.Thread.ThreadState == ThreadState.Stopped)
346 RemoveThread(threadInfo.Thread.ManagedThreadId);
348 if(callbackInfos == null)
349 callbackInfos =
new List<ThreadWatchdogInfo>();
351 callbackInfos.Add(threadInfo);
353 else if(!threadInfo.IsTimedOut && now - threadInfo.LastTick >= threadInfo.Timeout)
355 threadInfo.IsTimedOut =
true;
357 if(threadInfo.AlarmIfTimeout)
359 if(callbackInfos == null)
360 callbackInfos =
new List<ThreadWatchdogInfo>();
364 callbackInfos.Add(
new ThreadWatchdogInfo(threadInfo));
370 if(callbackInfos != null)
371 foreach (ThreadWatchdogInfo callbackInfo
in callbackInfos)
372 callback(callbackInfo);
375 if (MemoryWatchdog.Enabled)
376 MemoryWatchdog.Update();
378 ChecksManager.CheckChecks();
379 StatsManager.RecordStats();
381 m_watchdogTimer.Start();
Holds individual statistic details
ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi)
StatVerbosity
Verbosity of stat.
ThreadWatchdogInfo(Thread thread, int timeout, string name)
MeasuresOfInterest
Measures of interest for this stat.