diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs index 317b3a0946..97b3b60cce 100644 --- a/OpenSim/Framework/Communications/RestClient.cs +++ b/OpenSim/Framework/Communications/RestClient.cs @@ -403,7 +403,7 @@ namespace OpenSim.Framework.Communications /// In case, we are invoked asynchroneously this object will keep track of the state /// AsyncResult ar = new AsyncResult(callback, state); - ThreadPool.UnsafeQueueUserWorkItem(RequestHelper, ar); + Util.FireAndForget(RequestHelper, ar); return ar; } diff --git a/OpenSim/Framework/Parallel.cs b/OpenSim/Framework/Parallel.cs index ab2e108353..70eecdcdac 100644 --- a/OpenSim/Framework/Parallel.cs +++ b/OpenSim/Framework/Parallel.cs @@ -66,7 +66,7 @@ namespace OpenSim.Framework for (int i = 0; i < threadCount; i++) { - ThreadPool.UnsafeQueueUserWorkItem( + Util.FireAndForget( delegate(object o) { int threadIndex = (int)o; @@ -122,7 +122,7 @@ namespace OpenSim.Framework for (int i = 0; i < threadCount; i++) { - ThreadPool.UnsafeQueueUserWorkItem( + Util.FireAndForget( delegate(object o) { int threadIndex = (int)o; @@ -178,7 +178,7 @@ namespace OpenSim.Framework for (int i = 0; i < threadCount; i++) { - ThreadPool.UnsafeQueueUserWorkItem( + Util.FireAndForget( delegate(object o) { int threadIndex = (int)o; diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d5ae3b7ebd..02f6d12839 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -50,6 +50,18 @@ using OpenMetaverse.StructuredData; namespace OpenSim.Framework { + /// + /// The method used by Util.FireAndForget for asynchronously firing events + /// + public enum FireAndForgetMethod + { + UnsafeQueueUserWorkItem, + QueueUserWorkItem, + BeginInvoke, + SmartThreadPool, + Thread, + } + /// /// Miscellaneous utility functions /// @@ -70,7 +82,9 @@ namespace OpenSim.Framework public static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); - + + public static FireAndForgetMethod FireAndForgetMethod = FireAndForgetMethod.UnsafeQueueUserWorkItem; + /// /// Linear interpolates B<->C using percent A /// @@ -1273,7 +1287,7 @@ namespace OpenSim.Framework /// /// Created to work around a limitation in Mono with nested delegates /// - /*private class FireAndForgetWrapper + private class FireAndForgetWrapper { public void FireAndForget(System.Threading.WaitCallback callback) { @@ -1284,32 +1298,50 @@ namespace OpenSim.Framework { callback.BeginInvoke(obj, EndFireAndForget, callback); } - }*/ + + private static void EndFireAndForget(IAsyncResult ar) + { + System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; + + try { callback.EndInvoke(ar); } + catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } + + ar.AsyncWaitHandle.Close(); + } + } public static void FireAndForget(System.Threading.WaitCallback callback) { - //FireAndForgetWrapper wrapper = Singleton.GetInstance(); - //wrapper.FireAndForget(callback); - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null); + FireAndForget(callback, null); } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { - //FireAndForgetWrapper wrapper = Singleton.GetInstance(); - //wrapper.FireAndForget(callback, obj); - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + break; + case FireAndForgetMethod.QueueUserWorkItem: + System.Threading.ThreadPool.QueueUserWorkItem(callback, obj); + break; + case FireAndForgetMethod.BeginInvoke: + FireAndForgetWrapper wrapper = Singleton.GetInstance(); + wrapper.FireAndForget(callback, obj); + break; + case FireAndForgetMethod.SmartThreadPool: + Amib.Threading.SmartThreadPool stp = Singleton.GetInstance(); + stp.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.Start(obj); + break; + default: + throw new NotImplementedException(); + } } - /*private static void EndFireAndForget(IAsyncResult ar) - { - System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; - - try { callback.EndInvoke(ar); } - catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } - - ar.AsyncWaitHandle.Close(); - }*/ - #endregion FireAndForget Threading Pattern } } diff --git a/OpenSim/Grid/MessagingServer.Modules/MessageService.cs b/OpenSim/Grid/MessagingServer.Modules/MessageService.cs index 49f0fa8e09..8ad1e9cdde 100644 --- a/OpenSim/Grid/MessagingServer.Modules/MessageService.cs +++ b/OpenSim/Grid/MessagingServer.Modules/MessageService.cs @@ -148,8 +148,7 @@ namespace OpenSim.Grid.MessagingServer.Modules friendlistupdater.presence2 = receiver; friendlistupdater.OnGetRegionData += m_regionModule.GetRegionInfo; friendlistupdater.OnDone += PresenceUpdateDone; - WaitCallback cb = new WaitCallback(friendlistupdater.go); - ThreadPool.UnsafeQueueUserWorkItem(cb, null); + Util.FireAndForget(friendlistupdater.go); } else { diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 143dd2a2a0..5be1816c04 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -90,10 +90,17 @@ namespace OpenSim appender.File = fileName; appender.ActivateOptions(); } - m_log.InfoFormat("[LOGGING] Logging started to file {0}", appender.File); + m_log.InfoFormat("[LOGGING]: Logging started to file {0}", appender.File); } } + + string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty); + FireAndForgetMethod asyncCallMethod; + if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse(asyncCallMethodStr, out asyncCallMethod)) + Util.FireAndForgetMethod = asyncCallMethod; } + + m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } /// diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 432fee7dbd..0ba76ecd70 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -791,7 +791,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// heightmap public virtual void SendLayerData(float[] map) { - ThreadPool.UnsafeQueueUserWorkItem(DoSendLayerData, map); + Util.FireAndForget(DoSendLayerData, map); } /// @@ -931,7 +931,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 16x16 array of wind speeds public virtual void SendWindData(Vector2[] windSpeeds) { - ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSendWindData), (object)windSpeeds); + Util.FireAndForget(DoSendWindData, windSpeeds); } /// @@ -940,7 +940,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 16x16 array of cloud densities public virtual void SendCloudData(float[] cloudDensity) { - ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSendCloudData), (object)cloudDensity); + Util.FireAndForget(DoSendCloudData, cloudDensity); } /// diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index cbdca16e74..c6af8067a4 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -302,12 +302,8 @@ namespace Flotsam.RegionModules.AssetCache } - ThreadPool.UnsafeQueueUserWorkItem( - delegate - { - WriteFileCache(filename, asset); - }, null - ); + Util.FireAndForget( + delegate { WriteFileCache(filename, asset); }); } } catch (Exception e) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 126058454c..4e4008431f 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -1095,7 +1095,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // The reason is so we don't cause the thread to freeze waiting // for the 1 second it costs to start a thread manually. if (!threadrunning) - ThreadPool.UnsafeQueueUserWorkItem(this.StartThread, null); + Util.FireAndForget(this.StartThread); lock (m_rootAgents) { diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 2d56f4eaab..35b08f95d4 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -31,6 +31,15 @@ ; To run a script every few minutes, set the script filename here ; timer_Script = "filename" + + ; ## + ; ## SYSTEM + ; ## + + ; Sets the method that OpenSim will use to fire asynchronous + ; events. Valid values are UnsafeQueueUserWorkItem, + ; QueueUserWorkItem, BeginInvoke, SmartThreadPool, and Thread + async_call_method = UnsafeQueueUserWorkItem ; ## ; ## CLIENTS