diff options
author | Justin Clark-Casey (justincc) | 2012-07-31 23:57:57 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2012-07-31 23:57:57 +0100 |
commit | 7609daca388d1acbe8da7eaf407c0b3f4da1fd80 (patch) | |
tree | faaf03a514ab3227270cb83cdfb1d2c5a938714d /OpenSim | |
parent | Fix bug in SoundModule.TriggerSound() where every sound update to an avatar w... (diff) | |
download | opensim-SC-7609daca388d1acbe8da7eaf407c0b3f4da1fd80.zip opensim-SC-7609daca388d1acbe8da7eaf407c0b3f4da1fd80.tar.gz opensim-SC-7609daca388d1acbe8da7eaf407c0b3f4da1fd80.tar.bz2 opensim-SC-7609daca388d1acbe8da7eaf407c0b3f4da1fd80.tar.xz |
Resolve a deadlock between INPCModule and SensorRepeat by replacing the SensorRepeat list with a new list on add/removes rather than locking it for the duration of the sensor sweep.
A deadlock was observed today where NPC removal on a script thread would lock the NPC list and then try to lock the sensor list via scripted attachment removal.
Concurrently, the sensor sweep thread would lock the sensor list and then try to lock the NPC list to check NPC status.
This commit resolves the deadlock by replacing the sensor list on update rather than locking it for the duration of the sweep.
Diffstat (limited to 'OpenSim')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs | 78 |
1 files changed, 43 insertions, 35 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index f2c8b60..06495bb 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 | |||
51 | { | 51 | { |
52 | get | 52 | get |
53 | { | 53 | { |
54 | lock (SenseRepeatListLock) | 54 | return SenseRepeaters.Count; |
55 | return SenseRepeaters.Count; | ||
56 | } | 55 | } |
57 | } | 56 | } |
58 | 57 | ||
@@ -116,6 +115,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
116 | public double distance; | 115 | public double distance; |
117 | } | 116 | } |
118 | 117 | ||
118 | /// <summary> | ||
119 | /// Sensors to process. | ||
120 | /// </summary> | ||
121 | /// <remarks> | ||
122 | /// Do not add or remove sensors from this list directly. Instead, copy the list and substitute the updated | ||
123 | /// copy. This is to avoid locking the list for the duration of the sensor sweep, which increases the danger | ||
124 | /// of deadlocks with future code updates. | ||
125 | /// | ||
126 | /// Always lock SenseRepeatListLock when updating this list. | ||
127 | /// </remarks> | ||
119 | private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>(); | 128 | private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>(); |
120 | private object SenseRepeatListLock = new object(); | 129 | private object SenseRepeatListLock = new object(); |
121 | 130 | ||
@@ -125,6 +134,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
125 | { | 134 | { |
126 | // Always remove first, in case this is a re-set | 135 | // Always remove first, in case this is a re-set |
127 | UnSetSenseRepeaterEvents(m_localID, m_itemID); | 136 | UnSetSenseRepeaterEvents(m_localID, m_itemID); |
137 | |||
128 | if (sec == 0) // Disabling timer | 138 | if (sec == 0) // Disabling timer |
129 | return; | 139 | return; |
130 | 140 | ||
@@ -144,9 +154,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
144 | ts.host = host; | 154 | ts.host = host; |
145 | 155 | ||
146 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | 156 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); |
157 | |||
158 | AddSenseRepeater(ts); | ||
159 | } | ||
160 | |||
161 | private void AddSenseRepeater(SenseRepeatClass senseRepeater) | ||
162 | { | ||
147 | lock (SenseRepeatListLock) | 163 | lock (SenseRepeatListLock) |
148 | { | 164 | { |
149 | SenseRepeaters.Add(ts); | 165 | List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(SenseRepeaters); |
166 | newSenseRepeaters.Add(senseRepeater); | ||
167 | SenseRepeaters = newSenseRepeaters; | ||
150 | } | 168 | } |
151 | } | 169 | } |
152 | 170 | ||
@@ -155,39 +173,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
155 | // Remove from timer | 173 | // Remove from timer |
156 | lock (SenseRepeatListLock) | 174 | lock (SenseRepeatListLock) |
157 | { | 175 | { |
158 | List<SenseRepeatClass> NewSensors = new List<SenseRepeatClass>(); | 176 | List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(); |
159 | foreach (SenseRepeatClass ts in SenseRepeaters) | 177 | foreach (SenseRepeatClass ts in SenseRepeaters) |
160 | { | 178 | { |
161 | if (ts.localID != m_localID || ts.itemID != m_itemID) | 179 | if (ts.localID != m_localID || ts.itemID != m_itemID) |
162 | { | 180 | { |
163 | NewSensors.Add(ts); | 181 | newSenseRepeaters.Add(ts); |
164 | } | 182 | } |
165 | } | 183 | } |
166 | SenseRepeaters.Clear(); | 184 | |
167 | SenseRepeaters = NewSensors; | 185 | SenseRepeaters = newSenseRepeaters; |
168 | } | 186 | } |
169 | } | 187 | } |
170 | 188 | ||
171 | public void CheckSenseRepeaterEvents() | 189 | public void CheckSenseRepeaterEvents() |
172 | { | 190 | { |
173 | lock (SenseRepeatListLock) | 191 | // Go through all timers |
192 | foreach (SenseRepeatClass ts in SenseRepeaters) | ||
174 | { | 193 | { |
175 | // Nothing to do here? | 194 | // Time has passed? |
176 | if (SenseRepeaters.Count == 0) | 195 | if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) |
177 | return; | ||
178 | |||
179 | // Go through all timers | ||
180 | foreach (SenseRepeatClass ts in SenseRepeaters) | ||
181 | { | 196 | { |
182 | // Time has passed? | 197 | SensorSweep(ts); |
183 | if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) | 198 | // set next interval |
184 | { | 199 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); |
185 | SensorSweep(ts); | ||
186 | // set next interval | ||
187 | ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | ||
188 | } | ||
189 | } | 200 | } |
190 | } // lock | 201 | } |
191 | } | 202 | } |
192 | 203 | ||
193 | public void SenseOnce(uint m_localID, UUID m_itemID, | 204 | public void SenseOnce(uint m_localID, UUID m_itemID, |
@@ -615,21 +626,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
615 | { | 626 | { |
616 | List<Object> data = new List<Object>(); | 627 | List<Object> data = new List<Object>(); |
617 | 628 | ||
618 | lock (SenseRepeatListLock) | 629 | foreach (SenseRepeatClass ts in SenseRepeaters) |
619 | { | 630 | { |
620 | foreach (SenseRepeatClass ts in SenseRepeaters) | 631 | if (ts.itemID == itemID) |
621 | { | 632 | { |
622 | if (ts.itemID == itemID) | 633 | data.Add(ts.interval); |
623 | { | 634 | data.Add(ts.name); |
624 | data.Add(ts.interval); | 635 | data.Add(ts.keyID); |
625 | data.Add(ts.name); | 636 | data.Add(ts.type); |
626 | data.Add(ts.keyID); | 637 | data.Add(ts.range); |
627 | data.Add(ts.type); | 638 | data.Add(ts.arc); |
628 | data.Add(ts.range); | ||
629 | data.Add(ts.arc); | ||
630 | } | ||
631 | } | 639 | } |
632 | } | 640 | } |
641 | |||
633 | return data.ToArray(); | 642 | return data.ToArray(); |
634 | } | 643 | } |
635 | 644 | ||
@@ -663,8 +672,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
663 | ts.next = | 672 | ts.next = |
664 | DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | 673 | DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); |
665 | 674 | ||
666 | lock (SenseRepeatListLock) | 675 | AddSenseRepeater(ts); |
667 | SenseRepeaters.Add(ts); | ||
668 | 676 | ||
669 | idx += 6; | 677 | idx += 6; |
670 | } | 678 | } |