diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 828f2fbfb4..1dd50c7a40 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -107,6 +107,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private IXmlRpcRouter m_XmlRpcRouter;
private int m_EventLimit;
private bool m_KillTimedOutScripts;
+
+ ///
+ /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
+ /// its thread.
+ ///
+ ///
+ /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
+ /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
+ /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
+ /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
+ /// actually hold.
+ ///
+ /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
+ /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
+ /// shutting down.
+ ///
+ private int m_WaitForEventCompletionOnScriptStop = 1000;
+
private string m_ScriptEnginesPath = null;
private ExpiringCache m_runFlags = new ExpiringCache();
@@ -249,6 +267,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
+ m_WaitForEventCompletionOnScriptStop
+ = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
+
m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
m_Prio = ThreadPriority.BelowNormal;
@@ -1335,9 +1356,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
instance.ClearQueue();
- // Give the script some time to finish processing its last event. Simply aborting the script thread can
- // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
- instance.Stop(1000);
+ instance.Stop(m_WaitForEventCompletionOnScriptStop);
// bool objectRemoved = false;
@@ -1687,16 +1706,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
public void StopScript(UUID itemID)
{
IScriptInstance instance = GetInstance(itemID);
+
if (instance != null)
- {
- // Give the script some time to finish processing its last event. Simply aborting the script thread can
- // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
- instance.Stop(1000);
- }
+ instance.Stop(m_WaitForEventCompletionOnScriptStop);
else
- {
m_runFlags.AddOrUpdate(itemID, false, 240);
- }
}
public DetectParams GetDetectParams(UUID itemID, int idx)
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index e9bdabc7fe..284adfe387 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -1368,6 +1368,10 @@
; If a script overruns it's event limit, kill the script?
KillTimedOutScripts = false
+ ; Amount of time in milliseconds we will wait for an event to completely normally when a script stop is requested
+ ; before aborting the thread (such as when an object containing scripts is taken into inventory).
+ WaitForEventCompletionOnScriptStop = 1000;
+
; Sets the multiplier for the scripting delays
ScriptDelayFactor = 1.0