From e131e73652cf6ed2407e41c7d83dc67f49ca23ee Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Wed, 29 Jan 2014 16:14:27 +0200 Subject: [PATCH] Run slow operations in a separate thread, instead of using FireAndForget (which has a 1-minute timeout) Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 23 +++++++++++++++++++ .../Archiver/InventoryArchiveWriteRequest.cs | 2 +- .../LocalInventoryServiceConnector.cs | 4 ++-- .../World/Archiver/ArchiveWriteRequest.cs | 2 +- .../World/Archiver/AssetsRequest.cs | 6 ++--- OpenSim/Region/Framework/Scenes/Scene.cs | 6 ++--- .../Region/Framework/Scenes/ScenePresence.cs | 4 ++-- 7 files changed, 35 insertions(+), 12 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b39dc5f3bf..c9930fbeea 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2319,6 +2319,29 @@ namespace OpenSim.Framework #endregion FireAndForget Threading Pattern + /// + /// Run the callback on a different thread, outside the thread pool. This is used for tasks + /// that may take a long time. + /// + public static void RunThreadNoTimeout(WaitCallback callback, string name, object obj) + { + Thread t = new Thread(delegate() + { + try + { + Culture.SetCurrentCulture(); + callback(obj); + } + catch (Exception e) + { + m_log.Error("Exception in thread " + name, e); + } + }); + + t.Name = name; + t.Start(); + } + /// /// Environment.TickCount is an int but it counts all 32 bits so it goes positive /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index 429271916f..d15703eb73 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -356,7 +356,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, options, ReceivedAllAssets); - Util.FireAndForget(o => ar.Execute()); + Util.RunThreadNoTimeout(o => ar.Execute(), "AssetsRequest", null); } else { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index 99913a9b55..6832b1f06d 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -193,12 +193,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory // Protect ourselves against the caller subsequently modifying the items list List items = new List(invCol.Items); - Util.FireAndForget(delegate + Util.RunThreadNoTimeout(delegate { foreach (InventoryItemBase item in items) if (!string.IsNullOrEmpty(item.CreatorData)) UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); - }); + }, "GetFolderContent", null); } return invCol; diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index cd95ee9784..136a16e6c8 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs @@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_rootScene.AssetService, m_rootScene.UserAccountService, m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); - Util.FireAndForget(o => ar.Execute()); + Util.RunThreadNoTimeout(o => ar.Execute(), "AssetsRequest", null); // CloseArchive() will be called from ReceivedAllAssets() } diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index 2d0da61145..4f428c35a6 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs @@ -143,7 +143,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_requestState = RequestState.Running; m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired); - + // We can stop here if there are no assets to fetch if (m_repliesRequired == 0) { @@ -226,7 +226,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver finally { if (timedOut) - Util.FireAndForget(PerformAssetsRequestCallback, true); + Util.RunThreadNoTimeout(PerformAssetsRequestCallback, "AssetsRequestCallback", true); } } @@ -295,7 +295,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // We want to stop using the asset cache thread asap // as we now need to do the work of producing the rest of the archive - Util.FireAndForget(PerformAssetsRequestCallback, false); + Util.RunThreadNoTimeout(PerformAssetsRequestCallback, "AssetsRequestCallback", false); } else { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 51f6c5e6b8..726d8e261a 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1509,7 +1509,7 @@ namespace OpenSim.Region.Framework.Scenes { tmpMS = Util.EnvironmentTickCount(); m_cleaningTemps = true; - Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; }); + Util.RunThreadNoTimeout(delegate { CleanTempObjects(); m_cleaningTemps = false; }, "CleanTempObjects", null); tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS); } @@ -1682,7 +1682,7 @@ namespace OpenSim.Region.Framework.Scenes if (!m_backingup) { m_backingup = true; - Util.FireAndForget(BackupWaitCallback); + Util.RunThreadNoTimeout(BackupWaitCallback, "BackupWaitCallback", null); } } @@ -1695,7 +1695,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Wrapper for Backup() that can be called with Util.FireAndForget() + /// Wrapper for Backup() that can be called with Util.RunThreadNoTimeout() /// private void BackupWaitCallback(object o) { diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 64c464d761..080cdb4e37 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3201,7 +3201,7 @@ namespace OpenSim.Region.Framework.Scenes public void SendInitialDataToMe() { // Send all scene object to the new client - Util.FireAndForget(delegate + Util.RunThreadNoTimeout(delegate { // we created a new ScenePresence (a new child agent) in a fresh region. // Request info about all the (root) agents in this region @@ -3216,7 +3216,7 @@ namespace OpenSim.Region.Framework.Scenes ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); } - }); + }, "SendInitialDataToMe", null); } ///