aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-01-16 02:07:43 +0000
committerJustin Clark-Casey (justincc)2013-01-16 02:07:43 +0000
commit0963ece25bdef16852f5fd8ae4515a2f05d8b6e4 (patch)
treef95a3eef3e94df4408d555a30cd62bce629623f2 /OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
parentRevert "Implement co-operative script termination if termination comes during... (diff)
downloadopensim-SC_OLD-0963ece25bdef16852f5fd8ae4515a2f05d8b6e4.zip
opensim-SC_OLD-0963ece25bdef16852f5fd8ae4515a2f05d8b6e4.tar.gz
opensim-SC_OLD-0963ece25bdef16852f5fd8ae4515a2f05d8b6e4.tar.bz2
opensim-SC_OLD-0963ece25bdef16852f5fd8ae4515a2f05d8b6e4.tar.xz
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.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs54
1 files changed, 50 insertions, 4 deletions
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
200 200
201 public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; 201 public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute;
202 202
203 private bool m_coopTermination;
204
205 private EventWaitHandle m_coopSleepHandle;
206
203 public void ClearQueue() 207 public void ClearQueue()
204 { 208 {
205 m_TimerQueued = false; 209 m_TimerQueued = false;
@@ -233,6 +237,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
233 m_postOnRez = postOnRez; 237 m_postOnRez = postOnRez;
234 m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; 238 m_AttachedAvatar = Part.ParentGroup.AttachedAvatar;
235 m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; 239 m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID;
240
241 if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op")
242 {
243 m_coopTermination = true;
244 m_coopSleepHandle = new AutoResetEvent(false);
245 }
236 } 246 }
237 247
238 /// <summary> 248 /// <summary>
@@ -251,7 +261,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
251 foreach (string api in am.GetApis()) 261 foreach (string api in am.GetApis())
252 { 262 {
253 m_Apis[api] = am.CreateApi(api); 263 m_Apis[api] = am.CreateApi(api);
254 m_Apis[api].Initialize(this); 264 m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle);
255 } 265 }
256 266
257 try 267 try
@@ -532,9 +542,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
532 } 542 }
533 543
534 // Wait for the current event to complete. 544 // Wait for the current event to complete.
535 if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) 545 if (!m_InSelfDelete)
536 { 546 {
537 return true; 547 if (!m_coopTermination)
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 m_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 }
538 } 573 }
539 574
540 lock (EventQueue) 575 lock (EventQueue)
@@ -547,6 +582,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
547 582
548 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then 583 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then
549 // forcibly abort the work item (this aborts the underlying thread). 584 // forcibly abort the work item (this aborts the underlying thread).
585 // Co-operative termination should never reach this point.
550 if (!m_InSelfDelete) 586 if (!m_InSelfDelete)
551 { 587 {
552 m_log.DebugFormat( 588 m_log.DebugFormat(
@@ -786,7 +822,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
786 m_InEvent = false; 822 m_InEvent = false;
787 m_CurrentEvent = String.Empty; 823 m_CurrentEvent = String.Empty;
788 824
789 if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) 825 if ((!(e is TargetInvocationException)
826 || (!(e.InnerException is SelfDeleteException)
827 && !(e.InnerException is ScriptDeleteException)
828 && !(e.InnerException is ScriptCoopStopException)))
829 && !(e is ThreadAbortException))
790 { 830 {
791 try 831 try
792 { 832 {
@@ -834,6 +874,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
834 m_InSelfDelete = true; 874 m_InSelfDelete = true;
835 Part.Inventory.RemoveInventoryItem(ItemID); 875 Part.Inventory.RemoveInventoryItem(ItemID);
836 } 876 }
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 }
837 } 883 }
838 } 884 }
839 } 885 }