From 2f394b7e7ebf991c7a70f93bf251d26d8043aaa2 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 01:30:12 -0700 Subject: * Allow SmartThreadPool to be initialized without setting max stack size (like the original implementation) * Only initialize Util's SmartThreadPool if it is actually being used * No longer initializing Util's SmartThreadPool with a custom max stack size. From MSDN: "Avoid using this constructor overload. The default stack size used by the Thread(ThreadStart) constructor overload is the recommended stack size for threads." --- OpenSim/Framework/Util.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d09bd6d..167e34d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -69,8 +69,6 @@ namespace OpenSim.Framework /// public class Util { - private static SmartThreadPool m_ThreadPool = null; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static uint nextXferID = 5000; @@ -79,6 +77,9 @@ namespace OpenSim.Framework private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; private static object XferLock = new object(); + /// Thread pool used for Util.FireAndForget if + /// FireAndForgetMethod.SmartThreadPool is used + private static SmartThreadPool m_ThreadPool; // 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. private static readonly DateTime unixEpoch = @@ -1319,8 +1320,11 @@ namespace OpenSim.Framework FireAndForget(callback, null); } - public static void SetMaxThreads(int maxThreads) + public static void InitThreadPool(int maxThreads) { + if (maxThreads < 2) + throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (m_ThreadPool != null) return; @@ -1328,9 +1332,7 @@ namespace OpenSim.Framework startInfo.IdleTimeout = 2000; // 2 seconds startInfo.MaxWorkerThreads = maxThreads; startInfo.MinWorkerThreads = 2; - startInfo.StackSize = 524288; startInfo.ThreadPriority = ThreadPriority.Normal; - startInfo.StartSuspended = false; m_ThreadPool = new SmartThreadPool(startInfo); -- cgit v1.1 From d756fa01aea63e9b50be00a6f1f229ff7afef779 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Thu, 22 Oct 2009 18:57:14 +0900 Subject: Add copyright header. Formatting cleanup. --- OpenSim/Framework/MinHeap.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) mode change 100755 => 100644 OpenSim/Framework/MinHeap.cs (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/MinHeap.cs b/OpenSim/Framework/MinHeap.cs old mode 100755 new mode 100644 index ad39bbc..33d0364 --- a/OpenSim/Framework/MinHeap.cs +++ b/OpenSim/Framework/MinHeap.cs @@ -1,3 +1,30 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + using System; using System.Threading; using System.Collections; -- cgit v1.1 From 6ca4b0f36622833688136e9ace7d5545063293ba Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 10:37:11 -0700 Subject: * Added a check if Util.m_ThreadPool is null before trying to use it, and if so initialize it to sane defaults * Simplified the InitThreadPool() function --- OpenSim/Framework/Util.cs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 167e34d..a18a827 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1324,18 +1324,10 @@ namespace OpenSim.Framework { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); - if (m_ThreadPool != null) - return; - - STPStartInfo startInfo = new STPStartInfo(); - startInfo.IdleTimeout = 2000; // 2 seconds - startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 2; - startInfo.ThreadPriority = ThreadPriority.Normal; - startInfo.StartSuspended = false; + throw new InvalidOperationException("SmartThreadPool is already initialized"); - m_ThreadPool = new SmartThreadPool(startInfo); + m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) @@ -1343,20 +1335,22 @@ namespace OpenSim.Framework switch (FireAndForgetMethod) { case FireAndForgetMethod.UnsafeQueueUserWorkItem: - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + ThreadPool.UnsafeQueueUserWorkItem(callback, obj); break; case FireAndForgetMethod.QueueUserWorkItem: - System.Threading.ThreadPool.QueueUserWorkItem(callback, obj); + ThreadPool.QueueUserWorkItem(callback, obj); break; case FireAndForgetMethod.BeginInvoke: FireAndForgetWrapper wrapper = Singleton.GetInstance(); wrapper.FireAndForget(callback, obj); break; case FireAndForgetMethod.SmartThreadPool: + if (m_ThreadPool != null) + m_ThreadPool = new SmartThreadPool(2000, 15, 2); m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); break; case FireAndForgetMethod.Thread: - System.Threading.Thread thread = new System.Threading.Thread(delegate(object o) { callback(o); }); + Thread thread = new Thread(delegate(object o) { callback(o); }); thread.Start(obj); break; default: -- cgit v1.1 From 36b0e5e1d3112212ef988a8b2e7c10284c7e9276 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 11:07:23 -0700 Subject: Terrible typo in the previous commit! --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a18a827..b96367a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1345,7 +1345,7 @@ namespace OpenSim.Framework wrapper.FireAndForget(callback, obj); break; case FireAndForgetMethod.SmartThreadPool: - if (m_ThreadPool != null) + if (m_ThreadPool == null) m_ThreadPool = new SmartThreadPool(2000, 15, 2); m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); break; -- cgit v1.1 From b2ed348aa2746fbf034b713d006e40366c479d5a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 12:33:23 -0700 Subject: Implemented a Watchdog class. Do not manually create Thread objects anymore, use Watchdog.StartThread(). While your thread is running call Watchdog.UpdateThread(). When it is shutting down call Watchdog.RemoveThread(). Most of the threads in OpenSim have been updated --- .../Framework/Servers/HttpServer/BaseHttpServer.cs | 8 - .../HttpServer/PollServiceRequestManager.cs | 6 +- OpenSim/Framework/Watchdog.cs | 183 +++++++++++++++++++++ 3 files changed, 185 insertions(+), 12 deletions(-) create mode 100644 OpenSim/Framework/Watchdog.cs (limited to 'OpenSim/Framework') 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 public void Start() { m_log.Info("[HTTPD]: Starting up HTTP Server"); - - //m_workerThread = new Thread(new ThreadStart(StartHTTP)); - //m_workerThread.Name = "HttpThread"; - //m_workerThread.IsBackground = true; - //m_workerThread.Start(); - //ThreadTracker.Add(m_workerThread); StartHTTP(); - - } 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 m_WorkerThreadCount = pWorkerThreadCount; m_workerThreads = new Thread[m_WorkerThreadCount]; m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; - m_watcherThread = new Thread(ThreadStart); - //startup worker threads for (uint i=0;i + /// Manages launching threads and keeping watch over them for timeouts + /// + public static class Watchdog + { + /// Timer interval in milliseconds for the watchdog timer + const double WATCHDOG_INTERVAL_MS = 2500.0d; + /// Maximum timeout in milliseconds before a thread is considered dead + const int WATCHDOG_TIMEOUT_MS = 5000; + + [System.Diagnostics.DebuggerDisplay("{Thread.Name}")] + private class ThreadWatchdogInfo + { + public Thread Thread; + public int LastTick; + + public ThreadWatchdogInfo(Thread thread) + { + Thread = thread; + LastTick = Environment.TickCount & Int32.MaxValue; + } + } + + /// + /// This event is called whenever a tracked thread is stopped or + /// has not called UpdateThread() in time + /// + /// The thread that has been identified as dead + /// The last time this thread called UpdateThread() + public delegate void WatchdogTimeout(Thread thread, int lastTick); + + /// This event is called whenever a tracked thread is + /// stopped or has not called UpdateThread() in time + public static event WatchdogTimeout OnWatchdogTimeout; + + private static Dictionary m_threads; + private static System.Timers.Timer m_watchdogTimer; + + static Watchdog() + { + m_threads = new Dictionary(); + m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS); + m_watchdogTimer.AutoReset = false; + m_watchdogTimer.Elapsed += WatchdogTimerElapsed; + m_watchdogTimer.Start(); + } + + /// + /// Start a new thread that is tracked by the watchdog timer + /// + /// The method that will be executed in a new thread + /// A name to give to the new thread + /// Priority to run the thread at + /// True to run this thread as a background + /// thread, otherwise false + /// The newly created Thread object + public static Thread StartThread(ThreadStart start, string name, ThreadPriority priority, bool isBackground) + { + Thread thread = new Thread(start); + thread.Name = name; + thread.Priority = priority; + thread.IsBackground = isBackground; + thread.Start(); + + lock (m_threads) + m_threads.Add(thread.ManagedThreadId, new ThreadWatchdogInfo(thread)); + + return thread; + } + + /// + /// Marks the current thread as alive + /// + public static void UpdateThread() + { + UpdateThread(Thread.CurrentThread.ManagedThreadId); + } + + /// + /// Marks a thread as alive + /// + /// The ManagedThreadId of the thread to mark as + /// alive + public static void UpdateThread(int threadID) + { + ThreadWatchdogInfo threadInfo; + + lock (m_threads) + { + if (m_threads.TryGetValue(threadID, out threadInfo)) + { + threadInfo.LastTick = Environment.TickCount & Int32.MaxValue; + } + } + } + + /// + /// Stops watchdog tracking on the current thread + /// + /// True if the thread was removed from the list of tracked + /// threads, otherwise false + public static bool RemoveThread() + { + return RemoveThread(Thread.CurrentThread.ManagedThreadId); + } + + /// + /// Stops watchdog tracking on a thread + /// + /// The ManagedThreadId of the thread to stop + /// tracking + /// True if the thread was removed from the list of tracked + /// threads, otherwise false + public static bool RemoveThread(int threadID) + { + lock (m_threads) + return m_threads.Remove(threadID); + } + + private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) + { + WatchdogTimeout callback = OnWatchdogTimeout; + + if (callback != null) + { + ThreadWatchdogInfo timedOut = null; + + lock (m_threads) + { + int now = Environment.TickCount; + + foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) + { + if (threadInfo.Thread.ThreadState == ThreadState.Stopped || now - threadInfo.LastTick >= WATCHDOG_TIMEOUT_MS) + { + timedOut = threadInfo; + m_threads.Remove(threadInfo.Thread.ManagedThreadId); + break; + } + } + } + + if (timedOut != null) + callback(timedOut.Thread, timedOut.LastTick); + } + + m_watchdogTimer.Start(); + } + } +} -- cgit v1.1 From a41cd1d0695c01e4096fa0b7696b415a4c7455fc Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 23 Oct 2009 13:14:29 -0700 Subject: * Unregister Mono.Addins event handlers in PluginLoader.Dispose() and always handle PluginLoader with the using pattern. This freed up 121,634,796 bytes on my system * Avoid allocating an Action object every round of the OutgoingPacketHandler * Removed unnecessary semi-colon endings from OpenSim.ini.example [InterestManagement] section --- OpenSim/Framework/PluginLoader.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework') 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 } } + /// + /// Unregisters Mono.Addins event handlers, allowing temporary Mono.Addins + /// data to be garbage collected. Since the plugins created by this loader + /// are meant to outlive the loader itself, they must be disposed separately + /// public void Dispose() { - foreach (T plugin in Plugins) - plugin.Dispose(); + AddinManager.AddinLoadError -= on_addinloaderror_; + AddinManager.AddinLoaded -= on_addinloaded_; } private void initialise_plugin_dir_(string dir) -- cgit v1.1 From 52a4534f7fe9e7b044a54f5a794391b54a1edb94 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 23 Oct 2009 13:45:18 -0700 Subject: * Change the way Util.FireAndForget() calls SmartThreadPool to avoid using a delegate (which STP appears to hold on to). This removes the slow leak I was seeing when using async_call_method=SmartThreadPool and stabilizes allocated memory for an idle OpenSim instance --- OpenSim/Framework/Util.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b96367a..10f38ab 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1347,7 +1347,7 @@ namespace OpenSim.Framework case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) m_ThreadPool = new SmartThreadPool(2000, 15, 2); - m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); + m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { callback, obj }); break; case FireAndForgetMethod.Thread: Thread thread = new Thread(delegate(object o) { callback(o); }); @@ -1358,6 +1358,16 @@ namespace OpenSim.Framework } } + private static object SmartThreadPoolCallback(object o) + { + object[] array = (object[])o; + WaitCallback callback = (WaitCallback)array[0]; + object obj = array[1]; + + callback(obj); + return null; + } + #endregion FireAndForget Threading Pattern } } -- cgit v1.1 From 730930955a7edc0bfa69ff1cac93acd024cf8d24 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sun, 25 Oct 2009 00:40:21 -0700 Subject: Changing Scene.ForEachClient to use the synchronous for loop instead of Parallel. This is quite possibly the source of some deadlocking, and at the very least the synchronous version gives better stack traces * Lock the LLUDPClient RTO math * Add a helper function for backing off the RTO, and follow the optional advice in RFC 2988 to clear existing SRTT and RTTVAR values during a backoff * Removing the unused PrimitiveBaseShape.SculptImage parameter * Improved performance of SceneObjectPart instantiation * ZeroMesher now drops SculptData bytes like Meshmerizer, to allow the texture data to be GCed * Improved typecasting speed in MySQLLegacyRegionData.BuildShape() * Improved the instantiation of PrimitiveBaseShape --- OpenSim/Framework/PrimitiveBaseShape.cs | 66 +++++++++++++-------------------- 1 file changed, 25 insertions(+), 41 deletions(-) (limited to 'OpenSim/Framework') 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 { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly Primitive.TextureEntry m_defaultTexture; + private static readonly byte[] DEFAULT_TEXTURE = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f")).GetBytes(); private byte[] m_textureEntry; @@ -104,33 +104,32 @@ namespace OpenSim.Framework private HollowShape _hollowShape; // Sculpted - [XmlIgnore] private UUID _sculptTexture = UUID.Zero; - [XmlIgnore] private byte _sculptType = (byte)0; - [XmlIgnore] private byte[] _sculptData = new byte[0]; - [XmlIgnore] private Image _sculptBitmap = null; + [XmlIgnore] private UUID _sculptTexture; + [XmlIgnore] private byte _sculptType; + [XmlIgnore] private byte[] _sculptData = Utils.EmptyBytes; // Flexi - [XmlIgnore] private int _flexiSoftness = 0; - [XmlIgnore] private float _flexiTension = 0f; - [XmlIgnore] private float _flexiDrag = 0f; - [XmlIgnore] private float _flexiGravity = 0f; - [XmlIgnore] private float _flexiWind = 0f; - [XmlIgnore] private float _flexiForceX = 0f; - [XmlIgnore] private float _flexiForceY = 0f; - [XmlIgnore] private float _flexiForceZ = 0f; + [XmlIgnore] private int _flexiSoftness; + [XmlIgnore] private float _flexiTension; + [XmlIgnore] private float _flexiDrag; + [XmlIgnore] private float _flexiGravity; + [XmlIgnore] private float _flexiWind; + [XmlIgnore] private float _flexiForceX; + [XmlIgnore] private float _flexiForceY; + [XmlIgnore] private float _flexiForceZ; //Bright n sparkly - [XmlIgnore] private float _lightColorR = 0f; - [XmlIgnore] private float _lightColorG = 0f; - [XmlIgnore] private float _lightColorB = 0f; - [XmlIgnore] private float _lightColorA = 1f; - [XmlIgnore] private float _lightRadius = 0f; - [XmlIgnore] private float _lightCutoff = 0f; - [XmlIgnore] private float _lightFalloff = 0f; - [XmlIgnore] private float _lightIntensity = 1f; - [XmlIgnore] private bool _flexiEntry = false; - [XmlIgnore] private bool _lightEntry = false; - [XmlIgnore] private bool _sculptEntry = false; + [XmlIgnore] private float _lightColorR; + [XmlIgnore] private float _lightColorG; + [XmlIgnore] private float _lightColorB; + [XmlIgnore] private float _lightColorA = 1.0f; + [XmlIgnore] private float _lightRadius; + [XmlIgnore] private float _lightCutoff; + [XmlIgnore] private float _lightFalloff; + [XmlIgnore] private float _lightIntensity = 1.0f; + [XmlIgnore] private bool _flexiEntry; + [XmlIgnore] private bool _lightEntry; + [XmlIgnore] private bool _sculptEntry; public byte ProfileCurve { @@ -172,17 +171,11 @@ namespace OpenSim.Framework } } - static PrimitiveBaseShape() - { - m_defaultTexture = - new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f")); - } - public PrimitiveBaseShape() { PCode = (byte) PCodeEnum.Primitive; ExtraParams = new byte[1]; - Textures = m_defaultTexture; + m_textureEntry = DEFAULT_TEXTURE; } public PrimitiveBaseShape(bool noShape) @@ -192,7 +185,7 @@ namespace OpenSim.Framework PCode = (byte)PCodeEnum.Primitive; ExtraParams = new byte[1]; - Textures = m_defaultTexture; + m_textureEntry = DEFAULT_TEXTURE; } [XmlIgnore] @@ -577,15 +570,6 @@ namespace OpenSim.Framework } } - public Image SculptBitmap { - get { - return _sculptBitmap; - } - set { - _sculptBitmap = value; - } - } - public int FlexiSoftness { get { return _flexiSoftness; -- cgit v1.1 From ac7ccdf7d77810aef0a3ad70f1504fdb111dc0aa Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 26 Oct 2009 14:41:27 -0700 Subject: * Changed the watchdog timer to improve the speed of UpdateThread(), only track threads once the first call to UpdateThread() has been made, and allow re-tracking of threads that timed out but revived later * Added a commented out call to Watchdog.UpdateThread() in OdeScene. If it turns out that loading a large OAR file or some other operation is timing out the heartbeat thread, we'll need to uncomment it --- OpenSim/Framework/Watchdog.cs | 60 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs index b905609..5d46905 100644 --- a/OpenSim/Framework/Watchdog.cs +++ b/OpenSim/Framework/Watchdog.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Threading; +using log4net; namespace OpenSim.Framework { @@ -66,6 +67,7 @@ namespace OpenSim.Framework /// stopped or has not called UpdateThread() in time public static event WatchdogTimeout OnWatchdogTimeout; + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static Dictionary m_threads; private static System.Timers.Timer m_watchdogTimer; @@ -95,9 +97,6 @@ namespace OpenSim.Framework thread.IsBackground = isBackground; thread.Start(); - lock (m_threads) - m_threads.Add(thread.ManagedThreadId, new ThreadWatchdogInfo(thread)); - return thread; } @@ -110,24 +109,6 @@ namespace OpenSim.Framework } /// - /// Marks a thread as alive - /// - /// The ManagedThreadId of the thread to mark as - /// alive - public static void UpdateThread(int threadID) - { - ThreadWatchdogInfo threadInfo; - - lock (m_threads) - { - if (m_threads.TryGetValue(threadID, out threadInfo)) - { - threadInfo.LastTick = Environment.TickCount & Int32.MaxValue; - } - } - } - - /// /// Stops watchdog tracking on the current thread /// /// True if the thread was removed from the list of tracked @@ -137,19 +118,38 @@ namespace OpenSim.Framework return RemoveThread(Thread.CurrentThread.ManagedThreadId); } - /// - /// Stops watchdog tracking on a thread - /// - /// The ManagedThreadId of the thread to stop - /// tracking - /// True if the thread was removed from the list of tracked - /// threads, otherwise false - public static bool RemoveThread(int threadID) + private static void AddThread(ThreadWatchdogInfo threadInfo) + { + m_log.Debug("[WATCHDOG]: Started tracking thread \"" + threadInfo.Thread.Name + "\" (ID " + threadInfo.Thread.ManagedThreadId + ")"); + + lock (m_threads) + m_threads.Add(threadInfo.Thread.ManagedThreadId, threadInfo); + } + + private static bool RemoveThread(int threadID) { lock (m_threads) return m_threads.Remove(threadID); } + private static void UpdateThread(int threadID) + { + ThreadWatchdogInfo threadInfo; + + // Although TryGetValue is not a thread safe operation, we use a try/catch here instead + // of a lock for speed. Adding/removing threads is a very rare operation compared to + // UpdateThread(), and a single UpdateThread() failure here and there won't break + // anything + try + { + if (m_threads.TryGetValue(threadID, out threadInfo)) + threadInfo.LastTick = Environment.TickCount & Int32.MaxValue; + else + AddThread(new ThreadWatchdogInfo(Thread.CurrentThread)); + } + catch { } + } + private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) { WatchdogTimeout callback = OnWatchdogTimeout; @@ -160,7 +160,7 @@ namespace OpenSim.Framework lock (m_threads) { - int now = Environment.TickCount; + int now = Environment.TickCount & Int32.MaxValue; foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) { -- cgit v1.1 From 4847e62e9fd1cd473cc180220a379efba93f94a6 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 26 Oct 2009 16:33:04 -0700 Subject: * Switched all operations on the list of clients that could be either sync or async to use Scene.ForEachClient() instead of referencing ClientManager directly * Added a new [Startup] config option called use_async_when_possible to signal how to run operations that could be either sync or async * Changed Scene.ForEachClient to respect use_async_when_possible * Fixing a potential deadlock in Parallel.ForEach by locking on a temporary object instead of the enumerator (which may be shared across multiple invocations on ForEach). Thank you diva --- OpenSim/Framework/Parallel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework') 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 int counter = threadCount; AutoResetEvent threadFinishEvent = new AutoResetEvent(false); IEnumerator enumerator = enumerable.GetEnumerator(); + object syncRoot = new object(); Exception exception = null; for (int i = 0; i < threadCount; i++) @@ -131,7 +132,7 @@ namespace OpenSim.Framework { T entry; - lock (enumerator) + lock (syncRoot) { if (!enumerator.MoveNext()) break; -- cgit v1.1 From 0b1726b524934c2020aaf2b1f130219fb87003fd Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 26 Oct 2009 16:48:43 -0700 Subject: Removing the ClientManager reference from IScene and hiding it entirely inside Scene as an implementation detail. This will reduce programming error and make it easier to refactor the avatar vs client vs presence mess later on --- OpenSim/Framework/IScene.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim/Framework') 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 RegionInfo RegionInfo { get; } RegionStatus RegionStatus { get; set; } - ClientManager ClientManager { get; } IConfigSource Config { get; } float TimeDilation { get; } -- cgit v1.1 From c75d4156487b35aac47aa6818144862a99bb841c Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 27 Oct 2009 00:26:56 -0700 Subject: * Converts ClientManager.ForEach() (and as a result, Scene.ForEachClient()) to use a non-blocking parallel method when operating in async mode * Minor code readability cleanup --- OpenSim/Framework/ClientManager.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework') 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 public void ForEach(Action action) { IClientAPI[] localArray = m_array; - Parallel.ForEach(localArray, action); + Parallel.For(0, localArray.Length, + delegate(int i) + { action(localArray[i]); } + ); } /// -- cgit v1.1