aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-01-16 01:45:09 +0000
committerJustin Clark-Casey (justincc)2013-01-16 01:45:09 +0000
commitb8949024bc55c62b9268b35d4f2a568760b9d7d3 (patch)
tree7b8d984c957fab7aba5aceec66967adb5e8a0d51 /OpenSim/Region/ScriptEngine
parentMerge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff)
downloadopensim-SC_OLD-b8949024bc55c62b9268b35d4f2a568760b9d7d3.zip
opensim-SC_OLD-b8949024bc55c62b9268b35d4f2a568760b9d7d3.tar.gz
opensim-SC_OLD-b8949024bc55c62b9268b35d4f2a568760b9d7d3.tar.bz2
opensim-SC_OLD-b8949024bc55c62b9268b35d4f2a568760b9d7d3.tar.xz
Revert "Implement co-operative script termination if termination comes during a script wait event (llSleep(), etc.)"
Doing this as a favour to Melanie. This will be back with passing the wait handles directly to the api. This reverts commit 1b5c41c14ad11325be249ea1cce3c65d4d6a89be.
Diffstat (limited to 'OpenSim/Region/ScriptEngine')
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs31
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Helpers.cs18
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs52
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs157
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs5
6 files changed, 10 insertions, 266 deletions
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 38fff52..9de2d72 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -28,7 +28,6 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Threading;
32using OpenMetaverse; 31using OpenMetaverse;
33using log4net; 32using log4net;
34using OpenSim.Framework; 33using OpenSim.Framework;
@@ -182,18 +181,6 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
182 void Resume(); 181 void Resume();
183 182
184 /// <summary> 183 /// <summary>
185 /// If true then scripts should look to terminate their threads in co-operation with the script engine rather
186 /// than through Thread.Abort()
187 /// </summary>
188 bool CoopTermination { get; }
189
190 /// <summary>
191 /// Used for script sleeps when we are using co-operative script termination.
192 /// </summary>
193 /// <remarks>null if CoopTermination is not active</remarks>
194 EventWaitHandle CoopSleepHandle { get; }
195
196 /// <summary>
197 /// Process the next event queued for this script instance. 184 /// Process the next event queued for this script instance.
198 /// </summary> 185 /// </summary>
199 /// <returns></returns> 186 /// <returns></returns>
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
28using System;
29using System.Collections.Generic;
30using System.Threading;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Scripting.WorldComm;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.ScriptEngine.XEngine;
39using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41
42namespace 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
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index a17a018..186ae04 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -1716,14 +1716,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1716 IScriptInstance instance = GetInstance(itemID); 1716 IScriptInstance instance = GetInstance(itemID);
1717 1717
1718 if (instance != null) 1718 if (instance != null)
1719 {
1720 instance.Stop(m_WaitForEventCompletionOnScriptStop); 1719 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1721 }
1722 else 1720 else
1723 {
1724// m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name);
1725 m_runFlags.AddOrUpdate(itemID, false, 240); 1721 m_runFlags.AddOrUpdate(itemID, false, 240);
1726 }
1727 } 1722 }
1728 1723
1729 public DetectParams GetDetectParams(UUID itemID, int idx) 1724 public DetectParams GetDetectParams(UUID itemID, int idx)