diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared')
4 files changed, 10 insertions, 248 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index b992efa..44072c6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -83,12 +83,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
83 | public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi | 83 | public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi |
84 | { | 84 | { |
85 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 85 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
86 | |||
87 | /// <summary> | ||
88 | /// Instance of this script. | ||
89 | /// </summary> | ||
90 | protected IScriptInstance m_scriptInstance; | ||
91 | |||
92 | protected IScriptEngine m_ScriptEngine; | 86 | protected IScriptEngine m_ScriptEngine; |
93 | protected SceneObjectPart m_host; | 87 | protected SceneObjectPart m_host; |
94 | 88 | ||
@@ -118,12 +112,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
118 | 112 | ||
119 | public void Initialize(IScriptInstance scriptInstance) | 113 | public void Initialize(IScriptInstance scriptInstance) |
120 | { | 114 | { |
121 | m_scriptInstance = scriptInstance; | 115 | m_ScriptEngine = scriptInstance.Engine; |
122 | m_ScriptEngine = m_scriptInstance.Engine; | 116 | m_host = scriptInstance.Part; |
123 | m_host = m_scriptInstance.Part; | 117 | m_item = scriptInstance.ScriptTask; |
124 | m_item = m_scriptInstance.ScriptTask; | ||
125 | 118 | ||
126 | LoadConfig(); | 119 | LoadLimits(); // read script limits from config. |
127 | 120 | ||
128 | m_TransferModule = | 121 | m_TransferModule = |
129 | m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>(); | 122 | m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>(); |
@@ -136,7 +129,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
136 | /// <summary> | 129 | /// <summary> |
137 | /// Load configuration items that affect script, object and run-time behavior. */ | 130 | /// Load configuration items that affect script, object and run-time behavior. */ |
138 | /// </summary> | 131 | /// </summary> |
139 | private void LoadConfig() | 132 | private void LoadLimits() |
140 | { | 133 | { |
141 | m_ScriptDelayFactor = | 134 | m_ScriptDelayFactor = |
142 | m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); | 135 | m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); |
@@ -182,16 +175,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
182 | delay = (int)((float)delay * m_ScriptDelayFactor); | 175 | delay = (int)((float)delay * m_ScriptDelayFactor); |
183 | if (delay == 0) | 176 | if (delay == 0) |
184 | return; | 177 | return; |
185 | 178 | System.Threading.Thread.Sleep(delay); | |
186 | Sleep(delay); | ||
187 | } | ||
188 | |||
189 | protected virtual void Sleep(int delay) | ||
190 | { | ||
191 | if (!m_scriptInstance.CoopTermination) | ||
192 | System.Threading.Thread.Sleep(delay); | ||
193 | else if (m_scriptInstance.CoopSleepHandle.WaitOne(delay)) | ||
194 | throw new ScriptCoopStopException(); | ||
195 | } | 179 | } |
196 | 180 | ||
197 | public Scene World | 181 | public Scene World |
@@ -2930,8 +2914,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2930 | { | 2914 | { |
2931 | // m_log.Info("llSleep snoozing " + sec + "s."); | 2915 | // m_log.Info("llSleep snoozing " + sec + "s."); |
2932 | m_host.AddScriptLPS(1); | 2916 | m_host.AddScriptLPS(1); |
2933 | 2917 | Thread.Sleep((int)(sec * 1000)); | |
2934 | Sleep((int)(sec * 1000)); | ||
2935 | } | 2918 | } |
2936 | 2919 | ||
2937 | public LSL_Float llGetMass() | 2920 | public LSL_Float llGetMass() |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs index e02d35e..5a58f73 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs | |||
@@ -81,24 +81,6 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
81 | } | 81 | } |
82 | } | 82 | } |
83 | 83 | ||
84 | /// <summary> | ||
85 | /// Used to signal when the script is stopping in co-operation with the script engine | ||
86 | /// (instead of through Thread.Abort()). | ||
87 | /// </summary> | ||
88 | [Serializable] | ||
89 | public class ScriptCoopStopException : Exception | ||
90 | { | ||
91 | public ScriptCoopStopException() | ||
92 | { | ||
93 | } | ||
94 | |||
95 | protected ScriptCoopStopException( | ||
96 | SerializationInfo info, | ||
97 | StreamingContext context) | ||
98 | { | ||
99 | } | ||
100 | } | ||
101 | |||
102 | public class DetectParams | 84 | public class DetectParams |
103 | { | 85 | { |
104 | public const int AGENT = 1; | 86 | public const int AGENT = 1; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 00048a1..a2ff51b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -200,10 +200,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
200 | 200 | ||
201 | public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; | 201 | public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; |
202 | 202 | ||
203 | public bool CoopTermination { get; private set; } | ||
204 | |||
205 | public EventWaitHandle CoopSleepHandle { get; private set; } | ||
206 | |||
207 | public void ClearQueue() | 203 | public void ClearQueue() |
208 | { | 204 | { |
209 | m_TimerQueued = false; | 205 | m_TimerQueued = false; |
@@ -237,12 +233,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
237 | m_postOnRez = postOnRez; | 233 | m_postOnRez = postOnRez; |
238 | m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; | 234 | m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; |
239 | m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; | 235 | m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; |
240 | |||
241 | if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") | ||
242 | { | ||
243 | CoopTermination = true; | ||
244 | CoopSleepHandle = new AutoResetEvent(false); | ||
245 | } | ||
246 | } | 236 | } |
247 | 237 | ||
248 | /// <summary> | 238 | /// <summary> |
@@ -542,34 +532,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
542 | } | 532 | } |
543 | 533 | ||
544 | // Wait for the current event to complete. | 534 | // Wait for the current event to complete. |
545 | if (!m_InSelfDelete) | 535 | if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) |
546 | { | 536 | { |
547 | if (!CoopTermination) | 537 | return true; |
548 | { | ||
549 | // If we're not co-operative terminating then try and wait for the event to complete before stopping | ||
550 | if (workItem.Wait(new TimeSpan((long)timeout * 100000))) | ||
551 | return true; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | m_log.DebugFormat( | ||
556 | "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", | ||
557 | ScriptName, ItemID, PrimName, ObjectID); | ||
558 | |||
559 | // This will terminate the event on next handle check by the script. | ||
560 | CoopSleepHandle.Set(); | ||
561 | |||
562 | // For now, we will wait forever since the event should always cleanly terminate once LSL loop | ||
563 | // checking is implemented. May want to allow a shorter timeout option later. | ||
564 | if (workItem.Wait(TimeSpan.MaxValue)) | ||
565 | { | ||
566 | m_log.DebugFormat( | ||
567 | "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", | ||
568 | ScriptName, ItemID, PrimName, ObjectID); | ||
569 | |||
570 | return true; | ||
571 | } | ||
572 | } | ||
573 | } | 538 | } |
574 | 539 | ||
575 | lock (EventQueue) | 540 | lock (EventQueue) |
@@ -582,7 +547,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
582 | 547 | ||
583 | // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then | 548 | // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then |
584 | // forcibly abort the work item (this aborts the underlying thread). | 549 | // forcibly abort the work item (this aborts the underlying thread). |
585 | // Co-operative termination should never reach this point. | ||
586 | if (!m_InSelfDelete) | 550 | if (!m_InSelfDelete) |
587 | { | 551 | { |
588 | m_log.DebugFormat( | 552 | m_log.DebugFormat( |
@@ -822,11 +786,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
822 | m_InEvent = false; | 786 | m_InEvent = false; |
823 | m_CurrentEvent = String.Empty; | 787 | m_CurrentEvent = String.Empty; |
824 | 788 | ||
825 | if ((!(e is TargetInvocationException) | 789 | if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) |
826 | || (!(e.InnerException is SelfDeleteException) | ||
827 | && !(e.InnerException is ScriptDeleteException) | ||
828 | && !(e.InnerException is ScriptCoopStopException))) | ||
829 | && !(e is ThreadAbortException)) | ||
830 | { | 790 | { |
831 | try | 791 | try |
832 | { | 792 | { |
@@ -874,12 +834,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
874 | m_InSelfDelete = true; | 834 | m_InSelfDelete = true; |
875 | Part.Inventory.RemoveInventoryItem(ItemID); | 835 | Part.Inventory.RemoveInventoryItem(ItemID); |
876 | } | 836 | } |
877 | else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException)) | ||
878 | { | ||
879 | m_log.DebugFormat( | ||
880 | "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", | ||
881 | PrimName, ScriptName, data.EventName, State); | ||
882 | } | ||
883 | } | 837 | } |
884 | } | 838 | } |
885 | } | 839 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs deleted file mode 100644 index f3a6cc9..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ /dev/null | |||
@@ -1,157 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Threading; | ||
31 | using Nini.Config; | ||
32 | using NUnit.Framework; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.CoreModules.Scripting.WorldComm; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.ScriptEngine.XEngine; | ||
39 | using OpenSim.Tests.Common; | ||
40 | using OpenSim.Tests.Common.Mock; | ||
41 | |||
42 | namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Test that co-operative script thread termination is working correctly. | ||
46 | /// </summary> | ||
47 | [TestFixture] | ||
48 | public class CoopTerminationTests : OpenSimTestCase | ||
49 | { | ||
50 | private TestScene m_scene; | ||
51 | private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine; | ||
52 | |||
53 | private AutoResetEvent m_chatEvent = new AutoResetEvent(false); | ||
54 | private AutoResetEvent m_stoppedEvent = new AutoResetEvent(false); | ||
55 | |||
56 | private OSChatMessage m_osChatMessageReceived; | ||
57 | |||
58 | [TestFixtureSetUp] | ||
59 | public void Init() | ||
60 | { | ||
61 | //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); | ||
62 | // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); | ||
63 | m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); | ||
64 | |||
65 | IniConfigSource configSource = new IniConfigSource(); | ||
66 | |||
67 | IConfig startupConfig = configSource.AddConfig("Startup"); | ||
68 | startupConfig.Set("DefaultScriptEngine", "XEngine"); | ||
69 | |||
70 | IConfig xEngineConfig = configSource.AddConfig("XEngine"); | ||
71 | xEngineConfig.Set("Enabled", "true"); | ||
72 | xEngineConfig.Set("StartDelay", "0"); | ||
73 | |||
74 | // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call | ||
75 | // to AssemblyResolver.OnAssemblyResolve fails. | ||
76 | xEngineConfig.Set("AppDomainLoading", "false"); | ||
77 | |||
78 | xEngineConfig.Set("ScriptStopStrategy", "co-op"); | ||
79 | |||
80 | m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); | ||
81 | SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); | ||
82 | m_scene.StartScripts(); | ||
83 | } | ||
84 | |||
85 | /// <summary> | ||
86 | /// Test co-operative termination on derez of an object containing a script with a long-running event. | ||
87 | /// </summary> | ||
88 | /// <remarks> | ||
89 | /// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts | ||
90 | /// within the build itself. | ||
91 | /// </remarks> | ||
92 | [Test] | ||
93 | public void TestStopOnLongSleep() | ||
94 | { | ||
95 | TestHelpers.InMethod(); | ||
96 | TestHelpers.EnableLogging(); | ||
97 | |||
98 | UUID userId = TestHelpers.ParseTail(0x1); | ||
99 | // UUID objectId = TestHelpers.ParseTail(0x100); | ||
100 | // UUID itemId = TestHelpers.ParseTail(0x3); | ||
101 | string itemName = "TestStopOnObjectDerezLongSleep() Item"; | ||
102 | |||
103 | SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnObjectDerezLongSleep", 0x100); | ||
104 | m_scene.AddNewSceneObject(so, true); | ||
105 | |||
106 | InventoryItemBase itemTemplate = new InventoryItemBase(); | ||
107 | // itemTemplate.ID = itemId; | ||
108 | itemTemplate.Name = itemName; | ||
109 | itemTemplate.Folder = so.UUID; | ||
110 | itemTemplate.InvType = (int)InventoryType.LSL; | ||
111 | |||
112 | m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; | ||
113 | |||
114 | SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, | ||
115 | @"default | ||
116 | { | ||
117 | state_entry() | ||
118 | { | ||
119 | llSay(0, ""Thin Lizzy""); | ||
120 | llSleep(60); | ||
121 | } | ||
122 | }"); | ||
123 | |||
124 | TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); | ||
125 | |||
126 | // Wait for the script to start the event before we try stopping it. | ||
127 | m_chatEvent.WaitOne(60000); | ||
128 | |||
129 | Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); | ||
130 | |||
131 | // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script | ||
132 | // executes llSay() but has not started the sleep before we try to stop it. | ||
133 | Thread.Sleep(1000); | ||
134 | |||
135 | // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually | ||
136 | // stopped. This kind of multi-threading is far from ideal in a regression test. | ||
137 | new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); | ||
138 | |||
139 | if (!m_stoppedEvent.WaitOne(30000)) | ||
140 | Assert.Fail("Script did not co-operatively stop."); | ||
141 | |||
142 | bool running; | ||
143 | TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); | ||
144 | Assert.That( | ||
145 | SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); | ||
146 | Assert.That(running, Is.False); | ||
147 | } | ||
148 | |||
149 | private void OnChatFromWorld(object sender, OSChatMessage oscm) | ||
150 | { | ||
151 | // Console.WriteLine("Got chat [{0}]", oscm.Message); | ||
152 | |||
153 | m_osChatMessageReceived = oscm; | ||
154 | m_chatEvent.Set(); | ||
155 | } | ||
156 | } | ||
157 | } \ No newline at end of file | ||