diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index f2c8b6085a..06495bb1ba 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -51,8 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins { get { - lock (SenseRepeatListLock) - return SenseRepeaters.Count; + return SenseRepeaters.Count; } } @@ -116,6 +115,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public double distance; } + /// + /// Sensors to process. + /// + /// + /// Do not add or remove sensors from this list directly. Instead, copy the list and substitute the updated + /// copy. This is to avoid locking the list for the duration of the sensor sweep, which increases the danger + /// of deadlocks with future code updates. + /// + /// Always lock SenseRepeatListLock when updating this list. + /// private List SenseRepeaters = new List(); private object SenseRepeatListLock = new object(); @@ -125,6 +134,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins { // Always remove first, in case this is a re-set UnSetSenseRepeaterEvents(m_localID, m_itemID); + if (sec == 0) // Disabling timer return; @@ -144,9 +154,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins ts.host = host; ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); + + AddSenseRepeater(ts); + } + + private void AddSenseRepeater(SenseRepeatClass senseRepeater) + { lock (SenseRepeatListLock) { - SenseRepeaters.Add(ts); + List newSenseRepeaters = new List(SenseRepeaters); + newSenseRepeaters.Add(senseRepeater); + SenseRepeaters = newSenseRepeaters; } } @@ -155,39 +173,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Remove from timer lock (SenseRepeatListLock) { - List NewSensors = new List(); + List newSenseRepeaters = new List(); foreach (SenseRepeatClass ts in SenseRepeaters) { if (ts.localID != m_localID || ts.itemID != m_itemID) { - NewSensors.Add(ts); + newSenseRepeaters.Add(ts); } } - SenseRepeaters.Clear(); - SenseRepeaters = NewSensors; + + SenseRepeaters = newSenseRepeaters; } } public void CheckSenseRepeaterEvents() { - lock (SenseRepeatListLock) + // Go through all timers + foreach (SenseRepeatClass ts in SenseRepeaters) { - // Nothing to do here? - if (SenseRepeaters.Count == 0) - return; - - // Go through all timers - foreach (SenseRepeatClass ts in SenseRepeaters) + // Time has passed? + if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) { - // Time has passed? - if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) - { - SensorSweep(ts); - // set next interval - ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); - } + SensorSweep(ts); + // set next interval + ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); } - } // lock + } } public void SenseOnce(uint m_localID, UUID m_itemID, @@ -615,21 +626,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins { List data = new List(); - lock (SenseRepeatListLock) + foreach (SenseRepeatClass ts in SenseRepeaters) { - foreach (SenseRepeatClass ts in SenseRepeaters) + if (ts.itemID == itemID) { - if (ts.itemID == itemID) - { - data.Add(ts.interval); - data.Add(ts.name); - data.Add(ts.keyID); - data.Add(ts.type); - data.Add(ts.range); - data.Add(ts.arc); - } + data.Add(ts.interval); + data.Add(ts.name); + data.Add(ts.keyID); + data.Add(ts.type); + data.Add(ts.range); + data.Add(ts.arc); } } + return data.ToArray(); } @@ -663,8 +672,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); - lock (SenseRepeatListLock) - SenseRepeaters.Add(ts); + AddSenseRepeater(ts); idx += 6; }