aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework
diff options
context:
space:
mode:
authorMelanie2009-10-27 11:32:11 +0000
committerMelanie2009-10-27 11:32:11 +0000
commit31a848e97bd984ab0a85feca397ce419f6ae839a (patch)
tree4743f5eb7c12b3723ed4b986d19714d1b3a0a3ea /OpenSim/Framework
parentCommented out instrumentation in ODEPrim.cs (diff)
parentFinally hunted down the Parallel deadlock. Packets were being handled asynchr... (diff)
downloadopensim-SC-31a848e97bd984ab0a85feca397ce419f6ae839a.zip
opensim-SC-31a848e97bd984ab0a85feca397ce419f6ae839a.tar.gz
opensim-SC-31a848e97bd984ab0a85feca397ce419f6ae839a.tar.bz2
opensim-SC-31a848e97bd984ab0a85feca397ce419f6ae839a.tar.xz
Merge branch 'master' into vehicles
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/ClientManager.cs5
-rw-r--r--OpenSim/Framework/IScene.cs1
-rw-r--r--[-rwxr-xr-x]OpenSim/Framework/MinHeap.cs27
-rw-r--r--OpenSim/Framework/Parallel.cs3
-rw-r--r--OpenSim/Framework/PluginLoader.cs9
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs66
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs8
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs6
-rw-r--r--OpenSim/Framework/Servers/VersionInfo.cs4
-rw-r--r--OpenSim/Framework/Util.cs42
-rw-r--r--OpenSim/Framework/Watchdog.cs183
11 files changed, 276 insertions, 78 deletions
diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs
index 61b59e7..baff2f4 100644
--- a/OpenSim/Framework/ClientManager.cs
+++ b/OpenSim/Framework/ClientManager.cs
@@ -204,7 +204,10 @@ namespace OpenSim.Framework
204 public void ForEach(Action<IClientAPI> action) 204 public void ForEach(Action<IClientAPI> action)
205 { 205 {
206 IClientAPI[] localArray = m_array; 206 IClientAPI[] localArray = m_array;
207 Parallel.ForEach<IClientAPI>(localArray, action); 207 Parallel.For(0, localArray.Length,
208 delegate(int i)
209 { action(localArray[i]); }
210 );
208 } 211 }
209 212
210 /// <summary> 213 /// <summary>
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index f34027d..8067052 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -62,7 +62,6 @@ namespace OpenSim.Framework
62 RegionInfo RegionInfo { get; } 62 RegionInfo RegionInfo { get; }
63 RegionStatus RegionStatus { get; set; } 63 RegionStatus RegionStatus { get; set; }
64 64
65 ClientManager ClientManager { get; }
66 IConfigSource Config { get; } 65 IConfigSource Config { get; }
67 66
68 float TimeDilation { get; } 67 float TimeDilation { get; }
diff --git a/OpenSim/Framework/MinHeap.cs b/OpenSim/Framework/MinHeap.cs
index ad39bbc..33d0364 100755..100644
--- a/OpenSim/Framework/MinHeap.cs
+++ b/OpenSim/Framework/MinHeap.cs
@@ -1,3 +1,30 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
1using System; 28using System;
2using System.Threading; 29using System.Threading;
3using System.Collections; 30using System.Collections;
diff --git a/OpenSim/Framework/Parallel.cs b/OpenSim/Framework/Parallel.cs
index 70eecdc..515852f 100644
--- a/OpenSim/Framework/Parallel.cs
+++ b/OpenSim/Framework/Parallel.cs
@@ -118,6 +118,7 @@ namespace OpenSim.Framework
118 int counter = threadCount; 118 int counter = threadCount;
119 AutoResetEvent threadFinishEvent = new AutoResetEvent(false); 119 AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
120 IEnumerator<T> enumerator = enumerable.GetEnumerator(); 120 IEnumerator<T> enumerator = enumerable.GetEnumerator();
121 object syncRoot = new object();
121 Exception exception = null; 122 Exception exception = null;
122 123
123 for (int i = 0; i < threadCount; i++) 124 for (int i = 0; i < threadCount; i++)
@@ -131,7 +132,7 @@ namespace OpenSim.Framework
131 { 132 {
132 T entry; 133 T entry;
133 134
134 lock (enumerator) 135 lock (syncRoot)
135 { 136 {
136 if (!enumerator.MoveNext()) 137 if (!enumerator.MoveNext())
137 break; 138 break;
diff --git a/OpenSim/Framework/PluginLoader.cs b/OpenSim/Framework/PluginLoader.cs
index 5d38f5f..819cb7b 100644
--- a/OpenSim/Framework/PluginLoader.cs
+++ b/OpenSim/Framework/PluginLoader.cs
@@ -194,10 +194,15 @@ namespace OpenSim.Framework
194 } 194 }
195 } 195 }
196 196
197 /// <summary>
198 /// Unregisters Mono.Addins event handlers, allowing temporary Mono.Addins
199 /// data to be garbage collected. Since the plugins created by this loader
200 /// are meant to outlive the loader itself, they must be disposed separately
201 /// </summary>
197 public void Dispose() 202 public void Dispose()
198 { 203 {
199 foreach (T plugin in Plugins) 204 AddinManager.AddinLoadError -= on_addinloaderror_;
200 plugin.Dispose(); 205 AddinManager.AddinLoaded -= on_addinloaded_;
201 } 206 }
202 207
203 private void initialise_plugin_dir_(string dir) 208 private void initialise_plugin_dir_(string dir)
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs
index b646f92..5e4d175 100644
--- a/OpenSim/Framework/PrimitiveBaseShape.cs
+++ b/OpenSim/Framework/PrimitiveBaseShape.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Framework
76 { 76 {
77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
78 78
79 private static readonly Primitive.TextureEntry m_defaultTexture; 79 private static readonly byte[] DEFAULT_TEXTURE = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f")).GetBytes();
80 80
81 private byte[] m_textureEntry; 81 private byte[] m_textureEntry;
82 82
@@ -104,33 +104,32 @@ namespace OpenSim.Framework
104 private HollowShape _hollowShape; 104 private HollowShape _hollowShape;
105 105
106 // Sculpted 106 // Sculpted
107 [XmlIgnore] private UUID _sculptTexture = UUID.Zero; 107 [XmlIgnore] private UUID _sculptTexture;
108 [XmlIgnore] private byte _sculptType = (byte)0; 108 [XmlIgnore] private byte _sculptType;
109 [XmlIgnore] private byte[] _sculptData = new byte[0]; 109 [XmlIgnore] private byte[] _sculptData = Utils.EmptyBytes;
110 [XmlIgnore] private Image _sculptBitmap = null;
111 110
112 // Flexi 111 // Flexi
113 [XmlIgnore] private int _flexiSoftness = 0; 112 [XmlIgnore] private int _flexiSoftness;
114 [XmlIgnore] private float _flexiTension = 0f; 113 [XmlIgnore] private float _flexiTension;
115 [XmlIgnore] private float _flexiDrag = 0f; 114 [XmlIgnore] private float _flexiDrag;
116 [XmlIgnore] private float _flexiGravity = 0f; 115 [XmlIgnore] private float _flexiGravity;
117 [XmlIgnore] private float _flexiWind = 0f; 116 [XmlIgnore] private float _flexiWind;
118 [XmlIgnore] private float _flexiForceX = 0f; 117 [XmlIgnore] private float _flexiForceX;
119 [XmlIgnore] private float _flexiForceY = 0f; 118 [XmlIgnore] private float _flexiForceY;
120 [XmlIgnore] private float _flexiForceZ = 0f; 119 [XmlIgnore] private float _flexiForceZ;
121 120
122 //Bright n sparkly 121 //Bright n sparkly
123 [XmlIgnore] private float _lightColorR = 0f; 122 [XmlIgnore] private float _lightColorR;
124 [XmlIgnore] private float _lightColorG = 0f; 123 [XmlIgnore] private float _lightColorG;
125 [XmlIgnore] private float _lightColorB = 0f; 124 [XmlIgnore] private float _lightColorB;
126 [XmlIgnore] private float _lightColorA = 1f; 125 [XmlIgnore] private float _lightColorA = 1.0f;
127 [XmlIgnore] private float _lightRadius = 0f; 126 [XmlIgnore] private float _lightRadius;
128 [XmlIgnore] private float _lightCutoff = 0f; 127 [XmlIgnore] private float _lightCutoff;
129 [XmlIgnore] private float _lightFalloff = 0f; 128 [XmlIgnore] private float _lightFalloff;
130 [XmlIgnore] private float _lightIntensity = 1f; 129 [XmlIgnore] private float _lightIntensity = 1.0f;
131 [XmlIgnore] private bool _flexiEntry = false; 130 [XmlIgnore] private bool _flexiEntry;
132 [XmlIgnore] private bool _lightEntry = false; 131 [XmlIgnore] private bool _lightEntry;
133 [XmlIgnore] private bool _sculptEntry = false; 132 [XmlIgnore] private bool _sculptEntry;
134 133
135 public byte ProfileCurve 134 public byte ProfileCurve
136 { 135 {
@@ -172,17 +171,11 @@ namespace OpenSim.Framework
172 } 171 }
173 } 172 }
174 173
175 static PrimitiveBaseShape()
176 {
177 m_defaultTexture =
178 new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f"));
179 }
180
181 public PrimitiveBaseShape() 174 public PrimitiveBaseShape()
182 { 175 {
183 PCode = (byte) PCodeEnum.Primitive; 176 PCode = (byte) PCodeEnum.Primitive;
184 ExtraParams = new byte[1]; 177 ExtraParams = new byte[1];
185 Textures = m_defaultTexture; 178 m_textureEntry = DEFAULT_TEXTURE;
186 } 179 }
187 180
188 public PrimitiveBaseShape(bool noShape) 181 public PrimitiveBaseShape(bool noShape)
@@ -192,7 +185,7 @@ namespace OpenSim.Framework
192 185
193 PCode = (byte)PCodeEnum.Primitive; 186 PCode = (byte)PCodeEnum.Primitive;
194 ExtraParams = new byte[1]; 187 ExtraParams = new byte[1];
195 Textures = m_defaultTexture; 188 m_textureEntry = DEFAULT_TEXTURE;
196 } 189 }
197 190
198 [XmlIgnore] 191 [XmlIgnore]
@@ -577,15 +570,6 @@ namespace OpenSim.Framework
577 } 570 }
578 } 571 }
579 572
580 public Image SculptBitmap {
581 get {
582 return _sculptBitmap;
583 }
584 set {
585 _sculptBitmap = value;
586 }
587 }
588
589 public int FlexiSoftness { 573 public int FlexiSoftness {
590 get { 574 get {
591 return _flexiSoftness; 575 return _flexiSoftness;
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 85d7be2..bec5ed3 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -1559,15 +1559,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1559 public void Start() 1559 public void Start()
1560 { 1560 {
1561 m_log.Info("[HTTPD]: Starting up HTTP Server"); 1561 m_log.Info("[HTTPD]: Starting up HTTP Server");
1562
1563 //m_workerThread = new Thread(new ThreadStart(StartHTTP));
1564 //m_workerThread.Name = "HttpThread";
1565 //m_workerThread.IsBackground = true;
1566 //m_workerThread.Start();
1567 //ThreadTracker.Add(m_workerThread);
1568 StartHTTP(); 1562 StartHTTP();
1569
1570
1571 } 1563 }
1572 1564
1573 private void StartHTTP() 1565 private void StartHTTP()
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 1c54581..e7a64f7 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -50,9 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer
50 m_WorkerThreadCount = pWorkerThreadCount; 50 m_WorkerThreadCount = pWorkerThreadCount;
51 m_workerThreads = new Thread[m_WorkerThreadCount]; 51 m_workerThreads = new Thread[m_WorkerThreadCount];
52 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; 52 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
53 m_watcherThread = new Thread(ThreadStart);
54 53
55
56 //startup worker threads 54 //startup worker threads
57 for (uint i=0;i<m_WorkerThreadCount;i++) 55 for (uint i=0;i<m_WorkerThreadCount;i++)
58 { 56 {
@@ -65,11 +63,11 @@ namespace OpenSim.Framework.Servers.HttpServer
65 m_workerThreads[i].Start(); 63 m_workerThreads[i].Start();
66 64
67 } 65 }
66
68 //start watcher threads 67 //start watcher threads
68 m_watcherThread = new Thread(ThreadStart);
69 m_watcherThread.Name = "PollServiceWatcherThread"; 69 m_watcherThread.Name = "PollServiceWatcherThread";
70 m_watcherThread.Start(); 70 m_watcherThread.Start();
71
72
73 } 71 }
74 72
75 internal void ReQueueEvent(PollServiceHttpRequest req) 73 internal void ReQueueEvent(PollServiceHttpRequest req)
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index 62e7e92..9f98310 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/Servers/VersionInfo.cs
@@ -29,8 +29,8 @@ namespace OpenSim
29{ 29{
30 public class VersionInfo 30 public class VersionInfo
31 { 31 {
32 private const string VERSION_NUMBER = "0.6.7"; 32 private const string VERSION_NUMBER = "0.6.8";
33 private const Flavour VERSION_FLAVOUR = Flavour.RC1; 33 private const Flavour VERSION_FLAVOUR = Flavour.Dev;
34 34
35 public enum Flavour 35 public enum Flavour
36 { 36 {
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index d09bd6d..10f38ab 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -69,8 +69,6 @@ namespace OpenSim.Framework
69 /// </summary> 69 /// </summary>
70 public class Util 70 public class Util
71 { 71 {
72 private static SmartThreadPool m_ThreadPool = null;
73
74 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 72 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
75 73
76 private static uint nextXferID = 5000; 74 private static uint nextXferID = 5000;
@@ -79,6 +77,9 @@ namespace OpenSim.Framework
79 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; 77 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
80 private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; 78 private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]";
81 private static object XferLock = new object(); 79 private static object XferLock = new object();
80 /// <summary>Thread pool used for Util.FireAndForget if
81 /// FireAndForgetMethod.SmartThreadPool is used</summary>
82 private static SmartThreadPool m_ThreadPool;
82 83
83 // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. 84 // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.
84 private static readonly DateTime unixEpoch = 85 private static readonly DateTime unixEpoch =
@@ -1319,21 +1320,14 @@ namespace OpenSim.Framework
1319 FireAndForget(callback, null); 1320 FireAndForget(callback, null);
1320 } 1321 }
1321 1322
1322 public static void SetMaxThreads(int maxThreads) 1323 public static void InitThreadPool(int maxThreads)
1323 { 1324 {
1325 if (maxThreads < 2)
1326 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
1324 if (m_ThreadPool != null) 1327 if (m_ThreadPool != null)
1325 return; 1328 throw new InvalidOperationException("SmartThreadPool is already initialized");
1326
1327 STPStartInfo startInfo = new STPStartInfo();
1328 startInfo.IdleTimeout = 2000; // 2 seconds
1329 startInfo.MaxWorkerThreads = maxThreads;
1330 startInfo.MinWorkerThreads = 2;
1331 startInfo.StackSize = 524288;
1332 startInfo.ThreadPriority = ThreadPriority.Normal;
1333 1329
1334 startInfo.StartSuspended = false; 1330 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2);
1335
1336 m_ThreadPool = new SmartThreadPool(startInfo);
1337 } 1331 }
1338 1332
1339 public static void FireAndForget(System.Threading.WaitCallback callback, object obj) 1333 public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
@@ -1341,20 +1335,22 @@ namespace OpenSim.Framework
1341 switch (FireAndForgetMethod) 1335 switch (FireAndForgetMethod)
1342 { 1336 {
1343 case FireAndForgetMethod.UnsafeQueueUserWorkItem: 1337 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
1344 System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); 1338 ThreadPool.UnsafeQueueUserWorkItem(callback, obj);
1345 break; 1339 break;
1346 case FireAndForgetMethod.QueueUserWorkItem: 1340 case FireAndForgetMethod.QueueUserWorkItem:
1347 System.Threading.ThreadPool.QueueUserWorkItem(callback, obj); 1341 ThreadPool.QueueUserWorkItem(callback, obj);
1348 break; 1342 break;
1349 case FireAndForgetMethod.BeginInvoke: 1343 case FireAndForgetMethod.BeginInvoke:
1350 FireAndForgetWrapper wrapper = Singleton.GetInstance<FireAndForgetWrapper>(); 1344 FireAndForgetWrapper wrapper = Singleton.GetInstance<FireAndForgetWrapper>();
1351 wrapper.FireAndForget(callback, obj); 1345 wrapper.FireAndForget(callback, obj);
1352 break; 1346 break;
1353 case FireAndForgetMethod.SmartThreadPool: 1347 case FireAndForgetMethod.SmartThreadPool:
1354 m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); 1348 if (m_ThreadPool == null)
1349 m_ThreadPool = new SmartThreadPool(2000, 15, 2);
1350 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { callback, obj });
1355 break; 1351 break;
1356 case FireAndForgetMethod.Thread: 1352 case FireAndForgetMethod.Thread:
1357 System.Threading.Thread thread = new System.Threading.Thread(delegate(object o) { callback(o); }); 1353 Thread thread = new Thread(delegate(object o) { callback(o); });
1358 thread.Start(obj); 1354 thread.Start(obj);
1359 break; 1355 break;
1360 default: 1356 default:
@@ -1362,6 +1358,16 @@ namespace OpenSim.Framework
1362 } 1358 }
1363 } 1359 }
1364 1360
1361 private static object SmartThreadPoolCallback(object o)
1362 {
1363 object[] array = (object[])o;
1364 WaitCallback callback = (WaitCallback)array[0];
1365 object obj = array[1];
1366
1367 callback(obj);
1368 return null;
1369 }
1370
1365 #endregion FireAndForget Threading Pattern 1371 #endregion FireAndForget Threading Pattern
1366 } 1372 }
1367} 1373}
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs
new file mode 100644
index 0000000..5d46905
--- /dev/null
+++ b/OpenSim/Framework/Watchdog.cs
@@ -0,0 +1,183 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Threading;
31using log4net;
32
33namespace OpenSim.Framework
34{
35 /// <summary>
36 /// Manages launching threads and keeping watch over them for timeouts
37 /// </summary>
38 public static class Watchdog
39 {
40 /// <summary>Timer interval in milliseconds for the watchdog timer</summary>
41 const double WATCHDOG_INTERVAL_MS = 2500.0d;
42 /// <summary>Maximum timeout in milliseconds before a thread is considered dead</summary>
43 const int WATCHDOG_TIMEOUT_MS = 5000;
44
45 [System.Diagnostics.DebuggerDisplay("{Thread.Name}")]
46 private class ThreadWatchdogInfo
47 {
48 public Thread Thread;
49 public int LastTick;
50
51 public ThreadWatchdogInfo(Thread thread)
52 {
53 Thread = thread;
54 LastTick = Environment.TickCount & Int32.MaxValue;
55 }
56 }
57
58 /// <summary>
59 /// This event is called whenever a tracked thread is stopped or
60 /// has not called UpdateThread() in time
61 /// </summary>
62 /// <param name="thread">The thread that has been identified as dead</param>
63 /// <param name="lastTick">The last time this thread called UpdateThread()</param>
64 public delegate void WatchdogTimeout(Thread thread, int lastTick);
65
66 /// <summary>This event is called whenever a tracked thread is
67 /// stopped or has not called UpdateThread() in time</summary>
68 public static event WatchdogTimeout OnWatchdogTimeout;
69
70 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
71 private static Dictionary<int, ThreadWatchdogInfo> m_threads;
72 private static System.Timers.Timer m_watchdogTimer;
73
74 static Watchdog()
75 {
76 m_threads = new Dictionary<int, ThreadWatchdogInfo>();
77 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
78 m_watchdogTimer.AutoReset = false;
79 m_watchdogTimer.Elapsed += WatchdogTimerElapsed;
80 m_watchdogTimer.Start();
81 }
82
83 /// <summary>
84 /// Start a new thread that is tracked by the watchdog timer
85 /// </summary>
86 /// <param name="start">The method that will be executed in a new thread</param>
87 /// <param name="name">A name to give to the new thread</param>
88 /// <param name="priority">Priority to run the thread at</param>
89 /// <param name="isBackground">True to run this thread as a background
90 /// thread, otherwise false</param>
91 /// <returns>The newly created Thread object</returns>
92 public static Thread StartThread(ThreadStart start, string name, ThreadPriority priority, bool isBackground)
93 {
94 Thread thread = new Thread(start);
95 thread.Name = name;
96 thread.Priority = priority;
97 thread.IsBackground = isBackground;
98 thread.Start();
99
100 return thread;
101 }
102
103 /// <summary>
104 /// Marks the current thread as alive
105 /// </summary>
106 public static void UpdateThread()
107 {
108 UpdateThread(Thread.CurrentThread.ManagedThreadId);
109 }
110
111 /// <summary>
112 /// Stops watchdog tracking on the current thread
113 /// </summary>
114 /// <returns>True if the thread was removed from the list of tracked
115 /// threads, otherwise false</returns>
116 public static bool RemoveThread()
117 {
118 return RemoveThread(Thread.CurrentThread.ManagedThreadId);
119 }
120
121 private static void AddThread(ThreadWatchdogInfo threadInfo)
122 {
123 m_log.Debug("[WATCHDOG]: Started tracking thread \"" + threadInfo.Thread.Name + "\" (ID " + threadInfo.Thread.ManagedThreadId + ")");
124
125 lock (m_threads)
126 m_threads.Add(threadInfo.Thread.ManagedThreadId, threadInfo);
127 }
128
129 private static bool RemoveThread(int threadID)
130 {
131 lock (m_threads)
132 return m_threads.Remove(threadID);
133 }
134
135 private static void UpdateThread(int threadID)
136 {
137 ThreadWatchdogInfo threadInfo;
138
139 // Although TryGetValue is not a thread safe operation, we use a try/catch here instead
140 // of a lock for speed. Adding/removing threads is a very rare operation compared to
141 // UpdateThread(), and a single UpdateThread() failure here and there won't break
142 // anything
143 try
144 {
145 if (m_threads.TryGetValue(threadID, out threadInfo))
146 threadInfo.LastTick = Environment.TickCount & Int32.MaxValue;
147 else
148 AddThread(new ThreadWatchdogInfo(Thread.CurrentThread));
149 }
150 catch { }
151 }
152
153 private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
154 {
155 WatchdogTimeout callback = OnWatchdogTimeout;
156
157 if (callback != null)
158 {
159 ThreadWatchdogInfo timedOut = null;
160
161 lock (m_threads)
162 {
163 int now = Environment.TickCount & Int32.MaxValue;
164
165 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values)
166 {
167 if (threadInfo.Thread.ThreadState == ThreadState.Stopped || now - threadInfo.LastTick >= WATCHDOG_TIMEOUT_MS)
168 {
169 timedOut = threadInfo;
170 m_threads.Remove(threadInfo.Thread.ManagedThreadId);
171 break;
172 }
173 }
174 }
175
176 if (timedOut != null)
177 callback(timedOut.Thread, timedOut.LastTick);
178 }
179
180 m_watchdogTimer.Start();
181 }
182 }
183}