aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Watchdog.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Watchdog.cs')
-rw-r--r--OpenSim/Framework/Watchdog.cs66
1 files changed, 46 insertions, 20 deletions
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs
index 881b6aa..449d014 100644
--- a/OpenSim/Framework/Watchdog.cs
+++ b/OpenSim/Framework/Watchdog.cs
@@ -41,8 +41,8 @@ namespace OpenSim.Framework
41 /// <summary>Timer interval in milliseconds for the watchdog timer</summary> 41 /// <summary>Timer interval in milliseconds for the watchdog timer</summary>
42 const double WATCHDOG_INTERVAL_MS = 2500.0d; 42 const double WATCHDOG_INTERVAL_MS = 2500.0d;
43 43
44 /// <summary>Maximum timeout in milliseconds before a thread is considered dead</summary> 44 /// <summary>Default timeout in milliseconds before a thread is considered dead</summary>
45 const int WATCHDOG_TIMEOUT_MS = 5000; 45 public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000;
46 46
47 [System.Diagnostics.DebuggerDisplay("{Thread.Name}")] 47 [System.Diagnostics.DebuggerDisplay("{Thread.Name}")]
48 public class ThreadWatchdogInfo 48 public class ThreadWatchdogInfo
@@ -58,7 +58,7 @@ namespace OpenSim.Framework
58 public int FirstTick { get; private set; } 58 public int FirstTick { get; private set; }
59 59
60 /// <summary> 60 /// <summary>
61 /// First time this heartbeat update was invoked 61 /// Last time this heartbeat update was invoked
62 /// </summary> 62 /// </summary>
63 public int LastTick { get; set; } 63 public int LastTick { get; set; }
64 64
@@ -77,6 +77,11 @@ namespace OpenSim.Framework
77 /// </summary> 77 /// </summary>
78 public bool AlarmIfTimeout { get; set; } 78 public bool AlarmIfTimeout { get; set; }
79 79
80 /// <summary>
81 /// Method execute if alarm goes off. If null then no alarm method is fired.
82 /// </summary>
83 public Func<string> AlarmMethod { get; set; }
84
80 public ThreadWatchdogInfo(Thread thread, int timeout) 85 public ThreadWatchdogInfo(Thread thread, int timeout)
81 { 86 {
82 Thread = thread; 87 Thread = thread;
@@ -87,27 +92,33 @@ namespace OpenSim.Framework
87 } 92 }
88 93
89 /// <summary> 94 /// <summary>
90 /// This event is called whenever a tracked thread is stopped or 95 /// This event is called whenever a tracked thread is
91 /// has not called UpdateThread() in time 96 /// stopped or has not called UpdateThread() in time<
92 /// </summary> 97 /// /summary>
93 /// <param name="thread">The thread that has been identified as dead</param> 98 public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
94 /// <param name="lastTick">The last time this thread called UpdateThread()</param>
95 public delegate void WatchdogTimeout(Thread thread, int lastTick);
96
97 /// <summary>This event is called whenever a tracked thread is
98 /// stopped or has not called UpdateThread() in time</summary>
99 public static event WatchdogTimeout OnWatchdogTimeout;
100 99
101 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 100 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
102 private static Dictionary<int, ThreadWatchdogInfo> m_threads; 101 private static Dictionary<int, ThreadWatchdogInfo> m_threads;
103 private static System.Timers.Timer m_watchdogTimer; 102 private static System.Timers.Timer m_watchdogTimer;
104 103
104 /// <summary>
105 /// Last time the watchdog thread ran.
106 /// </summary>
107 /// <remarks>
108 /// Should run every WATCHDOG_INTERVAL_MS
109 /// </remarks>
110 public static int LastWatchdogThreadTick { get; private set; }
111
105 static Watchdog() 112 static Watchdog()
106 { 113 {
107 m_threads = new Dictionary<int, ThreadWatchdogInfo>(); 114 m_threads = new Dictionary<int, ThreadWatchdogInfo>();
108 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS); 115 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
109 m_watchdogTimer.AutoReset = false; 116 m_watchdogTimer.AutoReset = false;
110 m_watchdogTimer.Elapsed += WatchdogTimerElapsed; 117 m_watchdogTimer.Elapsed += WatchdogTimerElapsed;
118
119 // Set now so we don't get alerted on the first run
120 LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
121
111 m_watchdogTimer.Start(); 122 m_watchdogTimer.Start();
112 } 123 }
113 124
@@ -123,7 +134,7 @@ namespace OpenSim.Framework
123 public static Thread StartThread( 134 public static Thread StartThread(
124 ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout) 135 ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout)
125 { 136 {
126 return StartThread(start, name, priority, isBackground, alarmIfTimeout, WATCHDOG_TIMEOUT_MS); 137 return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS);
127 } 138 }
128 139
129 /// <summary> 140 /// <summary>
@@ -135,17 +146,24 @@ namespace OpenSim.Framework
135 /// <param name="isBackground">True to run this thread as a background 146 /// <param name="isBackground">True to run this thread as a background
136 /// thread, otherwise false</param> 147 /// thread, otherwise false</param>
137 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param> 148 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
149 /// <param name="alarmMethod">
150 /// Alarm method to call if alarmIfTimeout is true and there is a timeout.
151 /// Normally, this will just return some useful debugging information.
152 /// </param>
138 /// <param name="timeout">Number of milliseconds to wait until we issue a warning about timeout.</param> 153 /// <param name="timeout">Number of milliseconds to wait until we issue a warning about timeout.</param>
139 /// <returns>The newly created Thread object</returns> 154 /// <returns>The newly created Thread object</returns>
140 public static Thread StartThread( 155 public static Thread StartThread(
141 ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, int timeout) 156 ThreadStart start, string name, ThreadPriority priority, bool isBackground,
157 bool alarmIfTimeout, Func<string> alarmMethod, int timeout)
142 { 158 {
143 Thread thread = new Thread(start); 159 Thread thread = new Thread(start);
144 thread.Name = name; 160 thread.Name = name;
145 thread.Priority = priority; 161 thread.Priority = priority;
146 thread.IsBackground = isBackground; 162 thread.IsBackground = isBackground;
147 163
148 ThreadWatchdogInfo twi = new ThreadWatchdogInfo(thread, timeout) { AlarmIfTimeout = alarmIfTimeout }; 164 ThreadWatchdogInfo twi
165 = new ThreadWatchdogInfo(thread, timeout)
166 { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
149 167
150 m_log.DebugFormat( 168 m_log.DebugFormat(
151 "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId); 169 "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
@@ -258,7 +276,17 @@ namespace OpenSim.Framework
258 /// <param name="e"></param> 276 /// <param name="e"></param>
259 private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) 277 private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
260 { 278 {
261 WatchdogTimeout callback = OnWatchdogTimeout; 279 int now = Environment.TickCount & Int32.MaxValue;
280 int msElapsed = now - LastWatchdogThreadTick;
281
282 if (msElapsed > WATCHDOG_INTERVAL_MS * 2)
283 m_log.WarnFormat(
284 "[WATCHDOG]: {0} ms since Watchdog last ran. Interval should be approximately {1} ms",
285 msElapsed, WATCHDOG_INTERVAL_MS);
286
287 LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
288
289 Action<ThreadWatchdogInfo> callback = OnWatchdogTimeout;
262 290
263 if (callback != null) 291 if (callback != null)
264 { 292 {
@@ -266,8 +294,6 @@ namespace OpenSim.Framework
266 294
267 lock (m_threads) 295 lock (m_threads)
268 { 296 {
269 int now = Environment.TickCount;
270
271 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) 297 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values)
272 { 298 {
273 if (threadInfo.Thread.ThreadState == ThreadState.Stopped) 299 if (threadInfo.Thread.ThreadState == ThreadState.Stopped)
@@ -296,7 +322,7 @@ namespace OpenSim.Framework
296 322
297 if (callbackInfos != null) 323 if (callbackInfos != null)
298 foreach (ThreadWatchdogInfo callbackInfo in callbackInfos) 324 foreach (ThreadWatchdogInfo callbackInfo in callbackInfos)
299 callback(callbackInfo.Thread, callbackInfo.LastTick); 325 callback(callbackInfo);
300 } 326 }
301 327
302 m_watchdogTimer.Start(); 328 m_watchdogTimer.Start();