diff options
author | Justin Clark-Casey (justincc) | 2013-01-16 02:07:43 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2013-01-16 02:07:43 +0000 |
commit | 0963ece25bdef16852f5fd8ae4515a2f05d8b6e4 (patch) | |
tree | f95a3eef3e94df4408d555a30cd62bce629623f2 /OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |
parent | Revert "Implement co-operative script termination if termination comes during... (diff) | |
download | opensim-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.cs | 54 |
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 | } |