From f1b8fcaf47f3448a8fd4bdeee69c8db4df80cd8e Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 18 Jul 2013 20:00:11 +0200 Subject: [PATCH] Added ability to use SmartThreadPool --- OpenMetaverse/AgentManager.cs | 4 +- OpenMetaverse/AssetManager.cs | 2 +- OpenMetaverse/EventDictionary.cs | 8 +- OpenMetaverse/GridClient.cs | 3 + OpenMetaverse/GridManager.cs | 2 +- OpenMetaverse/ObjectManager.cs | 4 +- OpenMetaverse/TexturePipeline.cs | 2 +- OpenMetaverseTypes/Parallel.cs | 6 +- OpenMetaverseTypes/WorkPool.cs | 231 +++++++++++++++++++++++++++++++ bin/SmartThreadPool.dll | Bin 0 -> 66048 bytes 10 files changed, 248 insertions(+), 14 deletions(-) create mode 100644 OpenMetaverseTypes/WorkPool.cs create mode 100644 bin/SmartThreadPool.dll diff --git a/OpenMetaverse/AgentManager.cs b/OpenMetaverse/AgentManager.cs index 947d6f9c..6afb24eb 100644 --- a/OpenMetaverse/AgentManager.cs +++ b/OpenMetaverse/AgentManager.cs @@ -3943,7 +3943,7 @@ namespace OpenMetaverse if (m_AnimationsChanged != null) { - ThreadPool.QueueUserWorkItem(delegate(object o) + WorkPool.QueueUserWorkItem(delegate(object o) { OnAnimationsChanged(new AnimationsChangedEventArgs(this.SignaledAnimations)); }); } @@ -4338,7 +4338,7 @@ namespace OpenMetaverse return; } - ThreadPool.QueueUserWorkItem(sync => + WorkPool.QueueUserWorkItem(sync => { using (AutoResetEvent gotMuteList = new AutoResetEvent(false)) { diff --git a/OpenMetaverse/AssetManager.cs b/OpenMetaverse/AssetManager.cs index e8f88484..0589916d 100644 --- a/OpenMetaverse/AssetManager.cs +++ b/OpenMetaverse/AssetManager.cs @@ -901,7 +901,7 @@ namespace OpenMetaverse { Logger.Log("UploadBakedTexture not available, falling back to UDP method", Helpers.LogLevel.Info, Client); - ThreadPool.QueueUserWorkItem( + WorkPool.QueueUserWorkItem( delegate(object o) { UUID transactionID = UUID.Random(); diff --git a/OpenMetaverse/EventDictionary.cs b/OpenMetaverse/EventDictionary.cs index c5612aaa..cdd77149 100644 --- a/OpenMetaverse/EventDictionary.cs +++ b/OpenMetaverse/EventDictionary.cs @@ -144,7 +144,7 @@ namespace OpenMetaverse wrapper.Callback = callback.Callback; wrapper.Packet = packet; wrapper.Simulator = simulator; - ThreadPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); + WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); } else { @@ -164,7 +164,7 @@ namespace OpenMetaverse wrapper.Callback = callback.Callback; wrapper.Packet = packet; wrapper.Simulator = simulator; - ThreadPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); + WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); } else { @@ -329,7 +329,7 @@ namespace OpenMetaverse wrapper.CapsEvent = capsEvent; wrapper.Message = message; wrapper.Simulator = simulator; - ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); + WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); } } @@ -341,7 +341,7 @@ namespace OpenMetaverse wrapper.CapsEvent = capsEvent; wrapper.Message = message; wrapper.Simulator = simulator; - ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); + WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); specialHandler = true; } diff --git a/OpenMetaverse/GridClient.cs b/OpenMetaverse/GridClient.cs index de61b95e..f17e7b47 100644 --- a/OpenMetaverse/GridClient.cs +++ b/OpenMetaverse/GridClient.cs @@ -108,6 +108,9 @@ namespace OpenMetaverse /// public GridClient() { + // Initialise ThreadPool + WorkPool.Init(true); + // These are order-dependant Network = new NetworkManager(this); Settings = new Settings(this); diff --git a/OpenMetaverse/GridManager.cs b/OpenMetaverse/GridManager.cs index 678c3ceb..2594b25d 100644 --- a/OpenMetaverse/GridManager.cs +++ b/OpenMetaverse/GridManager.cs @@ -838,7 +838,7 @@ namespace OpenMetaverse if (m_CoarseLocationUpdate != null) { - ThreadPool.QueueUserWorkItem(delegate(object o) + WorkPool.QueueUserWorkItem(delegate(object o) { OnCoarseLocationUpdate(new CoarseLocationUpdateEventArgs(e.Simulator, newEntries, removedEntries)); }); } } diff --git a/OpenMetaverse/ObjectManager.cs b/OpenMetaverse/ObjectManager.cs index 52e1a62c..163dab40 100644 --- a/OpenMetaverse/ObjectManager.cs +++ b/OpenMetaverse/ObjectManager.cs @@ -2101,7 +2101,7 @@ namespace OpenMetaverse EventHandler handler = m_ObjectUpdate; if (handler != null) { - ThreadPool.QueueUserWorkItem(delegate(object o) + WorkPool.QueueUserWorkItem(delegate(object o) { handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNewObject, attachment)); }); } @@ -2320,7 +2320,7 @@ namespace OpenMetaverse EventHandler handler = m_TerseObjectUpdate; if (handler != null) { - ThreadPool.QueueUserWorkItem(delegate(object o) + WorkPool.QueueUserWorkItem(delegate(object o) { handler(this, new TerseObjectUpdateEventArgs(simulator, obj, update, terse.RegionData.TimeDilation)); }); } diff --git a/OpenMetaverse/TexturePipeline.cs b/OpenMetaverse/TexturePipeline.cs index fb25fde6..4fedd657 100644 --- a/OpenMetaverse/TexturePipeline.cs +++ b/OpenMetaverse/TexturePipeline.cs @@ -515,7 +515,7 @@ namespace OpenMetaverse nextTask.RequestSlot = slot; //Logger.DebugLog(String.Format("Sending Worker thread new download request {0}", slot)); - ThreadPool.QueueUserWorkItem(TextureRequestDoWork, nextTask); + WorkPool.QueueUserWorkItem(TextureRequestDoWork, nextTask); continue; } } diff --git a/OpenMetaverseTypes/Parallel.cs b/OpenMetaverseTypes/Parallel.cs index 4e49fc60..108fa35d 100644 --- a/OpenMetaverseTypes/Parallel.cs +++ b/OpenMetaverseTypes/Parallel.cs @@ -65,7 +65,7 @@ namespace OpenMetaverse for (int i = 0; i < threadCount; i++) { - ThreadPool.QueueUserWorkItem( + WorkPool.QueueUserWorkItem( delegate(object o) { int threadIndex = (int)o; @@ -120,7 +120,7 @@ namespace OpenMetaverse for (int i = 0; i < threadCount; i++) { - ThreadPool.QueueUserWorkItem( + WorkPool.QueueUserWorkItem( delegate(object o) { int threadIndex = (int)o; @@ -175,7 +175,7 @@ namespace OpenMetaverse for (int i = 0; i < threadCount; i++) { - ThreadPool.QueueUserWorkItem( + WorkPool.QueueUserWorkItem( delegate(object o) { int threadIndex = (int)o; diff --git a/OpenMetaverseTypes/WorkPool.cs b/OpenMetaverseTypes/WorkPool.cs new file mode 100644 index 00000000..6b64cda4 --- /dev/null +++ b/OpenMetaverseTypes/WorkPool.cs @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2007-2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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. + */ + +//#define SMARTHREADPOOL_REF + +using System; +using System.IO; +using System.Reflection; + +#if SMARTHREADPOOL_REF +using Amib.Threading; +#else +using System.Threading; +#endif + +namespace OpenMetaverse +{ + +// Use statically referenced SmartThreadPool.dll +#if SMARTHREADPOOL_REF + public static class WorkPool + { + internal static SmartThreadPool Pool = null; + + public static bool Init(bool useSmartThredPool) + { + if (Pool == null) + { + STPStartInfo param = new STPStartInfo(); + param.MinWorkerThreads = 2; + param.MaxWorkerThreads = 50; + param.ThreadPoolName = "LibOpenMetaverse Main ThreadPool"; + param.AreThreadsBackground = true; + + Pool = new SmartThreadPool(param); + } + return true; + } + + public static void Shutdown() + { + Pool.Shutdown(); + Pool = null; + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback) + { + if (Pool != null) + { + Pool.QueueWorkItem(state => { callback.Invoke(state); return null; }); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(state => callback.Invoke(state)); + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback, object state) + { + if (Pool != null) + { + Pool.QueueWorkItem(sync => { callback.Invoke(sync); return null; }, state); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + } + } + +#else + + // Try to load SmartThreadPool.dll during initialization + // Fallback to System.Threading.ThreadPool if that fails + public static class WorkPoolDynamic + { + internal static object Pool = null; + + private static Type SmartThreadPoolType; + private static Type WorkItemCallbackType; + private static MethodInfo QueueWorkItemFunc, QueueWorkItemFunc2; + private static MethodInfo ShutdownFunc; + private static Func Invoker; + + public static bool Init() + { + try + { + string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + Assembly assembly = Assembly.LoadFile(Path.Combine(dir, "SmartThreadPool.dll")); + Type STPStartInfo = assembly.GetType("Amib.Threading.STPStartInfo"); + SmartThreadPoolType = assembly.GetType("Amib.Threading.SmartThreadPool"); + WorkItemCallbackType = assembly.GetType("Amib.Threading.WorkItemCallback"); + var param = Activator.CreateInstance(STPStartInfo); + STPStartInfo.GetProperty("MinWorkerThreads").SetValue(param, 2, null); + STPStartInfo.GetProperty("MaxWorkerThreads").SetValue(param, 50, null); + STPStartInfo.GetProperty("ThreadPoolName").SetValue(param, "LibOpenMetaverse Main ThreadPool", null); + STPStartInfo.GetProperty("AreThreadsBackground").SetValue(param, true, null); + STPStartInfo.GetProperty("MinWorkerThreads").SetValue(param, 2, null); + Pool = Activator.CreateInstance(SmartThreadPoolType, new object[] { param }); + QueueWorkItemFunc = SmartThreadPoolType.GetMethod("QueueWorkItem", new Type[] { WorkItemCallbackType }); + QueueWorkItemFunc2 = SmartThreadPoolType.GetMethod("QueueWorkItem", new Type[] { WorkItemCallbackType, typeof(object) }); + ShutdownFunc = SmartThreadPoolType.GetMethod("Shutdown", new Type[] { }); + + Invoker = (inv, state) => + { + inv.Invoke(state); + return null; + }; + + return true; + } + catch + { + Pool = null; + return false; + } + } + + public static void Shutdown() + { + if (Pool != null) + { + ShutdownFunc.Invoke(Pool, null); + Pool = null; + } + } + + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback) + { + if (Pool != null) + { + QueueWorkItemFunc.Invoke(Pool, new object[] { Delegate.CreateDelegate(WorkItemCallbackType, callback, Invoker.Method) }); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(state => callback.Invoke(state)); + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback, object state) + { + if (Pool != null) + { + QueueWorkItemFunc2.Invoke(Pool, new object[] { Delegate.CreateDelegate(WorkItemCallbackType, callback, Invoker.Method), state }); + } + else + { + System.Threading.ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + } + } + + + public static class WorkPool + { + private static bool UseSmartThreadPool = false; + + public static bool Init(bool useSmartThredPool) + { + if (useSmartThredPool) + { + if (WorkPoolDynamic.Init()) + { + UseSmartThreadPool = true; + return true; + } + return false; + } + return true; + } + + public static void Shutdown() + { + if (UseSmartThreadPool) + { + WorkPoolDynamic.Shutdown(); + UseSmartThreadPool = false; + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback) + { + if (UseSmartThreadPool) + { + WorkPoolDynamic.QueueUserWorkItem(sync => callback.Invoke(sync)); + } + else + { + ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync)); + } + } + + public static void QueueUserWorkItem(System.Threading.WaitCallback callback, object state) + { + if (UseSmartThreadPool) + { + WorkPoolDynamic.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + else + { + ThreadPool.QueueUserWorkItem(sync => callback.Invoke(sync), state); + } + } + } +#endif +} diff --git a/bin/SmartThreadPool.dll b/bin/SmartThreadPool.dll new file mode 100644 index 0000000000000000000000000000000000000000..0b2f91d605170a93eaee49e97072b11a9f7aa202 GIT binary patch literal 66048 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 literal 0 HcmV?d00001