From 535ec23646053224acf17674d1d3479b68b8eb2f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 16 Jan 2013 02:07:43 +0000 Subject: [PATCH] Implement co-operative script termination if termination comes during a script wait event (llSleep(), etc.) This makes use of EventWaitHandles since various web references indicate that Thread.Interrupt() can also cause runtime instability. If co-op termination is enabled, then termination sets the wait handle instead of waiting for a timeout before possibly aborting the thread. This allows the script to cleanly terminate if it's in a llSleep/LL function delay or the next time it enters such a wait without any timeout period. Co-op termination is not yet testable since checking for termination request within loops that never trigger a wait is not yet implemented. This commit, unlike 1b5c41c, passes the wait handle as an extra parameter through IScript.Initialize() instead of passing IScriptInstance itself. --- .../Framework/Scenes/Scene.Inventory.cs | 26 ++- .../ScriptEngine/Interfaces/IScriptApi.cs | 9 +- .../Interfaces/IScriptInstance.cs | 1 + .../Shared/Api/Implementation/LSL_Api.cs | 35 +++- .../Shared/Api/Implementation/LS_Api.cs | 8 +- .../Shared/Api/Implementation/MOD_Api.cs | 10 +- .../Shared/Api/Implementation/OSSL_Api.cs | 10 +- OpenSim/Region/ScriptEngine/Shared/Helpers.cs | 18 ++ .../Shared/Instance/ScriptInstance.cs | 54 +++++- .../Instance/Tests/CoopTerminationTests.cs | 157 ++++++++++++++++++ .../Shared/Tests/LSL_ApiInventoryTests.cs | 6 +- .../Shared/Tests/LSL_ApiLinkingTests.cs | 4 +- .../Shared/Tests/LSL_ApiListTests.cs | 2 +- .../ScriptEngine/Shared/Tests/LSL_ApiTest.cs | 2 +- .../Shared/Tests/OSSL_ApiAppearanceTest.cs | 4 +- .../Shared/Tests/OSSL_ApiAttachmentTests.cs | 15 +- .../Shared/Tests/OSSL_ApiNpcTests.cs | 16 +- .../Region/ScriptEngine/XEngine/XEngine.cs | 5 + prebuild.xml | 5 +- 19 files changed, 332 insertions(+), 55 deletions(-) create mode 100644 OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 1e56bb70a9..12d70130ad 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1739,6 +1739,21 @@ namespace OpenSim.Region.Framework.Scenes /// /// The part where the script was rezzed if successful. False otherwise. public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) + { + return RezNewScript( + agentID, + itemBase, + "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"); + } + + /// + /// Rez a new script from nothing with given script text. + /// + /// + /// Template item. + /// + /// The part where the script was rezzed if successful. False otherwise. + public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText) { // The part ID is the folder ID! SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); @@ -1759,9 +1774,14 @@ namespace OpenSim.Region.Framework.Scenes return null; } - AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, - Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), - agentID); + AssetBase asset + = CreateAsset( + itemBase.Name, + itemBase.Description, + (sbyte)itemBase.AssetType, + Encoding.ASCII.GetBytes(scriptText), + agentID); + AssetService.Store(asset); TaskInventoryItem taskItem = new TaskInventoryItem(); diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index e95cbd7213..d2323f56d1 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs @@ -26,6 +26,7 @@ */ using System; +using System.Threading; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; @@ -40,7 +41,11 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// /// /// Each API has an identifier, which is used to load the proper runtime assembly at load time. - /// /param> - void Initialize(IScriptInstance scriptInstance); + /// /param> + /// /param> + /// /param> + /// /param> + void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle); } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 9de2d725f2..f68612c15e 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; using OpenMetaverse; using log4net; using OpenSim.Framework; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index a1f28f5422..79137b1b4b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -82,9 +82,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected IScriptEngine m_ScriptEngine; protected SceneObjectPart m_host; + /// + /// Used for script sleeps when we are using co-operative script termination. + /// + /// null if co-operative script termination is not active + EventWaitHandle m_coopSleepHandle; + /// /// The item that hosts this script /// @@ -107,13 +114,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected Dictionary m_userInfoCache = new Dictionary(); protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp. - public void Initialize(IScriptInstance scriptInstance) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = scriptInstance.Engine; - m_host = scriptInstance.Part; - m_item = scriptInstance.ScriptTask; + m_ScriptEngine = scriptEngine; + m_host = host; + m_item = item; + m_coopSleepHandle = coopSleepHandle; - LoadLimits(); // read script limits from config. + LoadConfig(); m_TransferModule = m_ScriptEngine.World.RequestModuleInterface(); @@ -125,7 +134,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// /// Load configuration items that affect script, object and run-time behavior. */ /// - private void LoadLimits() + private void LoadConfig() { m_ScriptDelayFactor = m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); @@ -166,7 +175,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api delay = (int)((float)delay * m_ScriptDelayFactor); if (delay == 0) return; - System.Threading.Thread.Sleep(delay); + + Sleep(delay); + } + + protected virtual void Sleep(int delay) + { + if (m_coopSleepHandle == null) + System.Threading.Thread.Sleep(delay); + else if (m_coopSleepHandle.WaitOne(delay)) + throw new ScriptCoopStopException(); } public Scene World @@ -2944,7 +2962,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // m_log.Info("llSleep snoozing " + sec + "s."); m_host.AddScriptLPS(1); - Thread.Sleep((int)(sec * 1000)); + + Sleep((int)(sec * 1000)); } public LSL_Float llGetMass() diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index e4fc9558cf..5c16b567d6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -30,6 +30,7 @@ using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Lifetime; +using System.Threading; using OpenMetaverse; using Nini.Config; using OpenSim; @@ -61,10 +62,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal bool m_LSFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptInstance scriptInstance) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = scriptInstance.Engine; - m_host = scriptInstance.Part; + m_ScriptEngine = scriptEngine; + m_host = host; if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) m_LSFunctionsEnabled = true; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 77b92c3904..44102e679e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -30,6 +30,7 @@ using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Lifetime; +using System.Threading; using OpenMetaverse; using Nini.Config; using OpenSim; @@ -61,11 +62,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal bool m_MODFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptInstance scriptInstance) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = scriptInstance.Engine; - m_host = scriptInstance.Part; - m_item = scriptInstance.ScriptTask; + m_ScriptEngine = scriptEngine; + m_host = host; + m_item = item; if (m_ScriptEngine.Config.GetBoolean("AllowMODFunctions", false)) m_MODFunctionsEnabled = true; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 2bcf013c75..2f80595d7c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -139,12 +139,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal float m_ScriptDelayFactor = 1.0f; internal float m_ScriptDistanceFactor = 1.0f; internal Dictionary m_FunctionPerms = new Dictionary(); + protected IUrlModule m_UrlModule = null; - public void Initialize(IScriptInstance scriptInstance) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = scriptInstance.Engine; - m_host = scriptInstance.Part; - m_item = scriptInstance.ScriptTask; + m_ScriptEngine = scriptEngine; + m_host = host; + m_item = item; if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) m_OSFunctionsEnabled = true; diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs index 0108f447f3..a3c2a47645 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs @@ -81,6 +81,24 @@ namespace OpenSim.Region.ScriptEngine.Shared } } + /// + /// Used to signal when the script is stopping in co-operation with the script engine + /// (instead of through Thread.Abort()). + /// + [Serializable] + public class ScriptCoopStopException : Exception + { + public ScriptCoopStopException() + { + } + + protected ScriptCoopStopException( + SerializationInfo info, + StreamingContext context) + { + } + } + public class DetectParams { public const int AGENT = 1; diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index a2ff51b59f..75aea2b0b1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -200,6 +200,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; + private bool m_coopTermination; + + private EventWaitHandle m_coopSleepHandle; + public void ClearQueue() { m_TimerQueued = false; @@ -233,6 +237,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_postOnRez = postOnRez; m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; + + if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") + { + m_coopTermination = true; + m_coopSleepHandle = new AutoResetEvent(false); + } } /// @@ -251,7 +261,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); - m_Apis[api].Initialize(this); + m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); } try @@ -532,9 +542,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } // Wait for the current event to complete. - if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) + if (!m_InSelfDelete) { - return true; + if (!m_coopTermination) + { + // If we're not co-operative terminating then try and wait for the event to complete before stopping + if (workItem.Wait(new TimeSpan((long)timeout * 100000))) + return true; + } + else + { + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); + + // This will terminate the event on next handle check by the script. + m_coopSleepHandle.Set(); + + // For now, we will wait forever since the event should always cleanly terminate once LSL loop + // checking is implemented. May want to allow a shorter timeout option later. + if (workItem.Wait(TimeSpan.MaxValue)) + { + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); + + return true; + } + } } lock (EventQueue) @@ -547,6 +582,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then // forcibly abort the work item (this aborts the underlying thread). + // Co-operative termination should never reach this point. if (!m_InSelfDelete) { m_log.DebugFormat( @@ -786,7 +822,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_InEvent = false; m_CurrentEvent = String.Empty; - if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) + if ((!(e is TargetInvocationException) + || (!(e.InnerException is SelfDeleteException) + && !(e.InnerException is ScriptDeleteException) + && !(e.InnerException is ScriptCoopStopException))) + && !(e is ThreadAbortException)) { try { @@ -834,6 +874,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_InSelfDelete = true; Part.Inventory.RemoveInventoryItem(ItemID); } + else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException)) + { + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", + PrimName, ScriptName, data.EventName, State); + } } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs new file mode 100644 index 0000000000..8c3e9e0b47 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -0,0 +1,157 @@ +/* + * 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.Collections.Generic; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.WorldComm; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests +{ + /// + /// Test that co-operative script thread termination is working correctly. + /// + [TestFixture] + public class CoopTerminationTests : OpenSimTestCase + { + private TestScene m_scene; + private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine; + + private AutoResetEvent m_chatEvent = new AutoResetEvent(false); + private AutoResetEvent m_stoppedEvent = new AutoResetEvent(false); + + private OSChatMessage m_osChatMessageReceived; + + [TestFixtureSetUp] + public void Init() + { + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); +// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); + m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); + + IniConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + xEngineConfig.Set("ScriptStopStrategy", "co-op"); + + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); + m_scene.StartScripts(); + } + + /// + /// Test co-operative termination on derez of an object containing a script with a long-running event. + /// + /// + /// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts + /// within the build itself. + /// + [Test] + public void TestStopOnLongSleep() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestStopOnObjectDerezLongSleep() Item"; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnObjectDerezLongSleep", 0x100); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + llSleep(60); + } +}"); + + TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + + // Wait for the script to start the event before we try stopping it. + m_chatEvent.WaitOne(60000); + + Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); + + // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script + // executes llSay() but has not started the sleep before we try to stop it. + Thread.Sleep(1000); + + // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually + // stopped. This kind of multi-threading is far from ideal in a regression test. + new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); + + if (!m_stoppedEvent.WaitOne(30000)) + Assert.Fail("Script did not co-operatively stop."); + + bool running; + TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + Assert.That( + SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); + Assert.That(running, Is.False); + } + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { +// Console.WriteLine("Got chat [{0}]", oscm.Message); + + m_osChatMessageReceived = oscm; + m_chatEvent.Set(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs index 36c75829a1..6dd6c170b7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs @@ -94,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); LSL_Api api = new LSL_Api(); - api.Initialize(new ScriptInstance(m_engine, so1.RootPart, null, 0, false, int.MaxValue)); + api.Initialize(m_engine, so1.RootPart, null, null); // Create a second object SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); @@ -127,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); m_scene.AddSceneObject(so1); LSL_Api api = new LSL_Api(); - api.Initialize(new ScriptInstance(m_engine, so1.RootPart, null, 0, false, int.MaxValue)); + api.Initialize(m_engine, so1.RootPart, null, null); // Create an object embedded inside the first UUID itemId = TestHelpers.ParseTail(0x20); @@ -137,7 +137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); m_scene.AddSceneObject(so2); LSL_Api api2 = new LSL_Api(); - api2.Initialize(new ScriptInstance(m_engine, so2.RootPart, null, 0, false, int.MaxValue)); + api2.Initialize(m_engine, so2.RootPart, null, null); // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs index 51213442cc..5b57bbe497 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs @@ -105,7 +105,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(grp2); LSL_Api apiGrp1 = new LSL_Api(); - apiGrp1.Initialize(new ScriptInstance(m_engine, grp1.RootPart, grp1Item, 0, false, int.MaxValue)); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null); apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); @@ -132,7 +132,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; LSL_Api apiGrp1 = new LSL_Api(); - apiGrp1.Initialize(new ScriptInstance(m_engine, grp1.RootPart, grp1Item, 0, false, int.MaxValue)); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null); apiGrp1.llBreakLink(2); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs index 28e58315b1..60de5cb62d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests engine.AddRegion(scene); m_lslApi = new LSL_Api(); - m_lslApi.Initialize(new ScriptInstance(engine, part, null, 0, false, int.MaxValue)); + m_lslApi.Initialize(engine, part, null, null); } [Test] diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index 48c2465825..e97ae06a7f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -67,7 +67,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests engine.AddRegion(scene); m_lslApi = new LSL_Api(); - m_lslApi.Initialize(new ScriptInstance(engine, part, null, 0, false, int.MaxValue)); + m_lslApi.Initialize(engine, part, null, null); } [Test] diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs index 5164d4e8f1..c88bad5dfc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs @@ -94,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; @@ -135,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs index e7b3319025..b2803a12c0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs @@ -99,10 +99,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); - ScriptInstance si = new ScriptInstance(m_engine, inWorldObj.RootPart, scriptItem, 0, false, int.MaxValue); - new LSL_Api().Initialize(si); + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(si); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); // SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); @@ -146,10 +145,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); - ScriptInstance si = new ScriptInstance(m_engine, inWorldObj.RootPart, scriptItem, 0, false, int.MaxValue); - new LSL_Api().Initialize(si); + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(si); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); // Create an object embedded inside the first TaskInventoryHelpers.AddNotecard( @@ -195,10 +193,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); - ScriptInstance si = new ScriptInstance(m_engine, inWorldObj.RootPart, scriptItem, 0, false, int.MaxValue); - new LSL_Api().Initialize(si); + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(si); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); // Create an object embedded inside the first TaskInventoryHelpers.AddSceneObject( diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index 584f44f12a..1f8a6e5b14 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs @@ -100,7 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -126,7 +126,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, so.RootPart, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, so.RootPart, null, null); bool gotExpectedException = false; try @@ -161,7 +161,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -195,7 +195,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); osslApi.osOwnerSaveAppearance(firstAppearanceNcName); @@ -233,7 +233,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); osslApi.osOwnerSaveAppearance(firstAppearanceNcName); @@ -285,10 +285,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(otherSo); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); OSSL_Api otherOsslApi = new OSSL_Api(); - otherOsslApi.Initialize(new ScriptInstance(m_engine, otherPart, null, 0, false, int.MaxValue)); + otherOsslApi.Initialize(m_engine, otherPart, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -332,7 +332,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(new ScriptInstance(m_engine, part, null, 0, false, int.MaxValue)); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index c2be37e435..82ddbec761 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1716,9 +1716,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = GetInstance(itemID); if (instance != null) + { instance.Stop(m_WaitForEventCompletionOnScriptStop); + } else + { +// m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); m_runFlags.AddOrUpdate(itemID, false, 240); + } } public DetectParams GetDetectParams(UUID itemID, int idx) diff --git a/prebuild.xml b/prebuild.xml index 078df6355f..529b494d96 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2372,7 +2372,9 @@ - + + + @@ -3262,6 +3264,7 @@ +