aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Monitoring/Watchdog.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Monitoring/Watchdog.cs')
-rw-r--r--OpenSim/Framework/Monitoring/Watchdog.cs149
1 files changed, 11 insertions, 138 deletions
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
index 0feec7c..a644fa5 100644
--- a/OpenSim/Framework/Monitoring/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -38,6 +38,8 @@ namespace OpenSim.Framework.Monitoring
38 /// </summary> 38 /// </summary>
39 public static class Watchdog 39 public static class Watchdog
40 { 40 {
41 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
42
41 /// <summary>Timer interval in milliseconds for the watchdog timer</summary> 43 /// <summary>Timer interval in milliseconds for the watchdog timer</summary>
42 public const double WATCHDOG_INTERVAL_MS = 2500.0d; 44 public const double WATCHDOG_INTERVAL_MS = 2500.0d;
43 45
@@ -133,8 +135,6 @@ namespace OpenSim.Framework.Monitoring
133 /// /summary> 135 /// /summary>
134 public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout; 136 public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
135 137
136 public static JobEngine JobEngine { get; private set; }
137
138 /// <summary> 138 /// <summary>
139 /// Is this watchdog active? 139 /// Is this watchdog active?
140 /// </summary> 140 /// </summary>
@@ -143,7 +143,7 @@ namespace OpenSim.Framework.Monitoring
143 get { return m_enabled; } 143 get { return m_enabled; }
144 set 144 set
145 { 145 {
146// m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value); 146 // m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value);
147 147
148 if (value == m_enabled) 148 if (value == m_enabled)
149 return; 149 return;
@@ -159,9 +159,8 @@ namespace OpenSim.Framework.Monitoring
159 m_watchdogTimer.Enabled = m_enabled; 159 m_watchdogTimer.Enabled = m_enabled;
160 } 160 }
161 } 161 }
162 private static bool m_enabled;
163 162
164 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 163 private static bool m_enabled;
165 private static Dictionary<int, ThreadWatchdogInfo> m_threads; 164 private static Dictionary<int, ThreadWatchdogInfo> m_threads;
166 private static System.Timers.Timer m_watchdogTimer; 165 private static System.Timers.Timer m_watchdogTimer;
167 166
@@ -175,7 +174,6 @@ namespace OpenSim.Framework.Monitoring
175 174
176 static Watchdog() 175 static Watchdog()
177 { 176 {
178 JobEngine = new JobEngine();
179 m_threads = new Dictionary<int, ThreadWatchdogInfo>(); 177 m_threads = new Dictionary<int, ThreadWatchdogInfo>();
180 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS); 178 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
181 m_watchdogTimer.AutoReset = false; 179 m_watchdogTimer.AutoReset = false;
@@ -183,94 +181,19 @@ namespace OpenSim.Framework.Monitoring
183 } 181 }
184 182
185 /// <summary> 183 /// <summary>
186 /// Start a new thread that is tracked by the watchdog timer. 184 /// Add a thread to the watchdog tracker.
187 /// </summary>
188 /// <param name="start">The method that will be executed in a new thread</param>
189 /// <param name="name">A name to give to the new thread</param>
190 /// <param name="priority">Priority to run the thread at</param>
191 /// <param name="isBackground">True to run this thread as a background thread, otherwise false</param>
192 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
193 /// <param name="log">If true then creation of thread is logged.</param>
194 /// <returns>The newly created Thread object</returns>
195 public static Thread StartThread(
196 ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, bool log = true)
197 {
198 return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS, log);
199 }
200
201 /// <summary>
202 /// Start a new thread that is tracked by the watchdog
203 /// </summary> 185 /// </summary>
204 /// <param name="start">The method that will be executed in a new thread</param> 186 /// <param name="info">Information about the thread.</info>
205 /// <param name="name">A name to give to the new thread</param> 187 /// <param name="info">Name of the thread.</info>
206 /// <param name="priority">Priority to run the thread at</param>
207 /// <param name="isBackground">True to run this thread as a background
208 /// thread, otherwise false</param>
209 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
210 /// <param name="alarmMethod">
211 /// Alarm method to call if alarmIfTimeout is true and there is a timeout.
212 /// Normally, this will just return some useful debugging information.
213 /// </param>
214 /// <param name="timeout">Number of milliseconds to wait until we issue a warning about timeout.</param>
215 /// <param name="log">If true then creation of thread is logged.</param> 188 /// <param name="log">If true then creation of thread is logged.</param>
216 /// <returns>The newly created Thread object</returns> 189 public static void AddThread(ThreadWatchdogInfo info, string name, bool log = true)
217 public static Thread StartThread(
218 ThreadStart start, string name, ThreadPriority priority, bool isBackground,
219 bool alarmIfTimeout, Func<string> alarmMethod, int timeout, bool log = true)
220 { 190 {
221 Thread thread = new Thread(start);
222 thread.Priority = priority;
223 thread.IsBackground = isBackground;
224
225 ThreadWatchdogInfo twi
226 = new ThreadWatchdogInfo(thread, timeout, name)
227 { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
228
229 if (log) 191 if (log)
230 m_log.DebugFormat( 192 m_log.DebugFormat(
231 "[WATCHDOG]: Started tracking thread {0}, ID {1}", name, twi.Thread.ManagedThreadId); 193 "[WATCHDOG]: Started tracking thread {0}, ID {1}", name, info.Thread.ManagedThreadId);
232 194
233 lock (m_threads) 195 lock (m_threads)
234 m_threads.Add(twi.Thread.ManagedThreadId, twi); 196 m_threads.Add(info.Thread.ManagedThreadId, info);
235
236 thread.Start();
237 thread.Name = name;
238
239
240 return thread;
241 }
242
243 /// <summary>
244 /// Run the callback in a new thread immediately. If the thread exits with an exception log it but do
245 /// not propogate it.
246 /// </summary>
247 /// <param name="callback">Code for the thread to execute.</param>
248 /// <param name="name">Name of the thread</param>
249 /// <param name="obj">Object to pass to the thread.</param>
250 public static void RunInThread(WaitCallback callback, string name, object obj, bool log = false)
251 {
252 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
253 {
254 Culture.SetCurrentCulture();
255 callback(obj);
256 return;
257 }
258
259 ThreadStart ts = new ThreadStart(delegate()
260 {
261 try
262 {
263 Culture.SetCurrentCulture();
264 callback(obj);
265 Watchdog.RemoveThread(log:false);
266 }
267 catch (Exception e)
268 {
269 m_log.Error(string.Format("[WATCHDOG]: Exception in thread {0}.", name), e);
270 }
271 });
272
273 StartThread(ts, name, ThreadPriority.Normal, true, false, log:log);
274 } 197 }
275 198
276 /// <summary> 199 /// <summary>
@@ -361,7 +284,7 @@ namespace OpenSim.Framework.Monitoring
361 } 284 }
362 catch { } 285 catch { }
363 } 286 }
364 287
365 /// <summary> 288 /// <summary>
366 /// Get currently watched threads for diagnostic purposes 289 /// Get currently watched threads for diagnostic purposes
367 /// </summary> 290 /// </summary>
@@ -453,55 +376,5 @@ namespace OpenSim.Framework.Monitoring
453 376
454 m_watchdogTimer.Start(); 377 m_watchdogTimer.Start();
455 } 378 }
456
457 /// <summary>
458 /// Run a job.
459 /// </summary>
460 /// <remarks>
461 /// This differs from direct scheduling (e.g. Util.FireAndForget) in that a job can be run in the job
462 /// engine if it is running, where all jobs are currently performed in sequence on a single thread. This is
463 /// to prevent observed overload and server freeze problems when there are hundreds of connections which all attempt to
464 /// perform work at once (e.g. in conference situations). With lower numbers of connections, the small
465 /// delay in performing jobs in sequence rather than concurrently has not been notiecable in testing, though a future more
466 /// sophisticated implementation could perform jobs concurrently when the server is under low load.
467 ///
468 /// However, be advised that some callers of this function rely on all jobs being performed in sequence if any
469 /// jobs are performed in sequence (i.e. if jobengine is active or not). Therefore, expanding the jobengine
470 /// beyond a single thread will require considerable thought.
471 ///
472 /// Also, any jobs submitted must be guaranteed to complete within a reasonable timeframe (e.g. they cannot
473 /// incorporate a network delay with a long timeout). At the moment, work that could suffer such issues
474 /// should still be run directly with RunInThread(), Util.FireAndForget(), etc. This is another area where
475 /// the job engine could be improved and so CPU utilization improved by better management of concurrency within
476 /// OpenSimulator.
477 /// </remarks>
478 /// <param name="jobType">General classification for the job (e.g. "RezAttachments").</param>
479 /// <param name="callback">Callback for job.</param>
480 /// <param name="name">Specific name of job (e.g. "RezAttachments for Joe Bloggs"</param>
481 /// <param name="obj">Object to pass to callback when run</param>
482 /// <param name="canRunInThisThread">If set to true then the job may be run in ths calling thread.</param>
483 /// <param name="mustNotTimeout">If the true then the job must never timeout.</param>
484 /// <param name="log">If set to true then extra logging is performed.</param>
485 public static void RunJob(
486 string jobType, WaitCallback callback, string name, object obj,
487 bool canRunInThisThread = false, bool mustNotTimeout = false,
488 bool log = false)
489 {
490 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
491 {
492 Culture.SetCurrentCulture();
493 callback(obj);
494 return;
495 }
496
497 if (JobEngine.IsRunning)
498 JobEngine.QueueRequest(name, callback, obj);
499 else if (canRunInThisThread)
500 callback(obj);
501 else if (mustNotTimeout)
502 RunInThread(callback, name, obj, log);
503 else
504 Util.FireAndForget(callback, obj, name);
505 }
506 } 379 }
507} \ No newline at end of file 380} \ No newline at end of file