From fccb03227e3f541a4c2f4e0e619074e4c1fb55dd Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Tue, 15 Jan 2013 21:13:22 +0000
Subject: Instead of passing separate engine, part and item components to
script APIs, pass down IScriptInstance instead.
This is to allow the future co-operative script thread terminate feature to detect and act upon termination requests.
This splits the assembly and state loading out from the ScriptInstance() constructor to a separate Load() method
in order to facilititate continued script logic regression testing.
---
.../ScriptEngine/Shared/Instance/ScriptInstance.cs | 52 ++++++++++++----------
1 file changed, 29 insertions(+), 23 deletions(-)
(limited to 'OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs')
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index f172216..a2ff51b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -157,9 +157,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public UUID AppDomain { get; set; }
- ///
- /// Scene part in which this script instance is contained.
- ///
public SceneObjectPart Part { get; private set; }
public string PrimName { get; private set; }
@@ -209,43 +206,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
EventQueue.Clear();
}
- public ScriptInstance(IScriptEngine engine, SceneObjectPart part,
- UUID itemID, UUID assetID, string assembly,
- AppDomain dom, string primName, string scriptName,
- int startParam, bool postOnRez, StateSource stateSource,
- int maxScriptQueue)
+ public ScriptInstance(
+ IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item,
+ int startParam, bool postOnRez,
+ int maxScriptQueue)
{
State = "default";
EventQueue = new Queue(32);
Engine = engine;
Part = part;
- ItemID = itemID;
- AssetID = assetID;
- PrimName = primName;
- ScriptName = scriptName;
- m_Assembly = assembly;
+ ScriptTask = item;
+
+ // This is currently only here to allow regression tests to get away without specifying any inventory
+ // item when they are testing script logic that doesn't require an item.
+ if (ScriptTask != null)
+ {
+ ScriptName = ScriptTask.Name;
+ ItemID = ScriptTask.ItemID;
+ AssetID = ScriptTask.AssetID;
+ }
+
+ PrimName = part.ParentGroup.Name;
StartParam = startParam;
m_MaxScriptQueue = maxScriptQueue;
- m_stateSource = stateSource;
m_postOnRez = postOnRez;
m_AttachedAvatar = Part.ParentGroup.AttachedAvatar;
m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID;
+ }
- lock (Part.TaskInventory)
- {
- if (Part.TaskInventory.ContainsKey(ItemID))
- {
- ScriptTask = Part.TaskInventory[ItemID];
- }
- }
+ ///
+ /// Load the script from an assembly into an AppDomain.
+ ///
+ ///
+ ///
+ ///
+ public void Load(AppDomain dom, string assembly, StateSource stateSource)
+ {
+ m_Assembly = assembly;
+ m_stateSource = stateSource;
ApiManager am = new ApiManager();
foreach (string api in am.GetApis())
{
m_Apis[api] = am.CreateApi(api);
- m_Apis[api].Initialize(engine, part, ScriptTask);
+ m_Apis[api].Initialize(this);
}
try
@@ -279,7 +285,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// // m_log.Debug("[Script] Script instance created");
- part.SetScriptEvents(ItemID,
+ Part.SetScriptEvents(ItemID,
(int)m_Script.GetStateEventFlags(State));
}
catch (Exception e)
--
cgit v1.1
From 1b5c41c14ad11325be249ea1cce3c65d4d6a89be Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 16 Jan 2013 00:12:40 +0000
Subject: 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.
---
.../ScriptEngine/Shared/Instance/ScriptInstance.cs | 52 ++++++++++++++++++++--
1 file changed, 49 insertions(+), 3 deletions(-)
(limited to 'OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs')
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index a2ff51b..00048a1 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;
+ public bool CoopTermination { get; private set; }
+
+ public EventWaitHandle CoopSleepHandle { get; private set; }
+
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")
+ {
+ CoopTermination = true;
+ CoopSleepHandle = new AutoResetEvent(false);
+ }
}
///
@@ -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 (!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.
+ 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);
+ }
}
}
}
--
cgit v1.1
From b8949024bc55c62b9268b35d4f2a568760b9d7d3 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 16 Jan 2013 01:45:09 +0000
Subject: 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.
---
.../ScriptEngine/Shared/Instance/ScriptInstance.cs | 52 ++--------------------
1 file changed, 3 insertions(+), 49 deletions(-)
(limited to 'OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs')
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
public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute;
- public bool CoopTermination { get; private set; }
-
- public EventWaitHandle CoopSleepHandle { get; private set; }
-
public void ClearQueue()
{
m_TimerQueued = false;
@@ -237,12 +233,6 @@ 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")
- {
- CoopTermination = true;
- CoopSleepHandle = new AutoResetEvent(false);
- }
}
///
@@ -542,34 +532,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
}
// Wait for the current event to complete.
- if (!m_InSelfDelete)
+ if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000)))
{
- if (!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.
- 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;
- }
- }
+ return true;
}
lock (EventQueue)
@@ -582,7 +547,6 @@ 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(
@@ -822,11 +786,7 @@ 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.InnerException is ScriptCoopStopException)))
- && !(e is ThreadAbortException))
+ if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException))
{
try
{
@@ -874,12 +834,6 @@ 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);
- }
}
}
}
--
cgit v1.1
From 0963ece25bdef16852f5fd8ae4515a2f05d8b6e4 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 16 Jan 2013 02:07:43 +0000
Subject: 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.
---
.../ScriptEngine/Shared/Instance/ScriptInstance.cs | 54 ++++++++++++++++++++--
1 file changed, 50 insertions(+), 4 deletions(-)
(limited to 'OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs')
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index a2ff51b..75aea2b 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);
+ }
}
}
}
--
cgit v1.1