diff options
author | Justin Clark-Casey (justincc) | 2013-01-16 00:12:40 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2013-01-16 00:12:40 +0000 |
commit | 1b5c41c14ad11325be249ea1cce3c65d4d6a89be (patch) | |
tree | 987e140c9402c48cc8daf59d2b8af165646cc93a /OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |
parent | Instead of passing separate engine, part and item components to script APIs, ... (diff) | |
download | opensim-SC_OLD-1b5c41c14ad11325be249ea1cce3c65d4d6a89be.zip opensim-SC_OLD-1b5c41c14ad11325be249ea1cce3c65d4d6a89be.tar.gz opensim-SC_OLD-1b5c41c14ad11325be249ea1cce3c65d4d6a89be.tar.bz2 opensim-SC_OLD-1b5c41c14ad11325be249ea1cce3c65d4d6a89be.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.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 52 |
1 files changed, 49 insertions, 3 deletions
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 | |||
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 | |||
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 | CoopTermination = true; | ||
244 | CoopSleepHandle = new AutoResetEvent(false); | ||
245 | } | ||
236 | } | 246 | } |
237 | 247 | ||
238 | /// <summary> | 248 | /// <summary> |
@@ -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 (!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 | 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 | } |