diff options
Diffstat (limited to 'OpenSim/Framework/Watchdog.cs')
-rw-r--r-- | OpenSim/Framework/Watchdog.cs | 66 |
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(); |