Lock around EventQueue manipulation in ScriptInstance.SetState() as queues are not thread-safe structures.

This should also make it less likely that an event will be erroneously posted during a state change by precluding a race condition with a thread calling ScriptInstance.PostEvent()
inv-download
Justin Clark-Casey (justincc) 2015-03-12 00:07:01 +00:00
parent b4b13510e8
commit 7410924de0
1 changed files with 24 additions and 17 deletions

View File

@ -619,13 +619,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (state == State) if (state == State)
return; return;
// Remove all queued events, remembering the last timer event
EventParams lastTimerEv = null; EventParams lastTimerEv = null;
lock (EventQueue)
{
// Remove all queued events, remembering the last timer event
while (EventQueue.Count > 0) while (EventQueue.Count > 0)
{ {
EventParams tempv = (EventParams)EventQueue.Dequeue(); EventParams tempv = (EventParams)EventQueue.Dequeue();
if (tempv.EventName == "timer") lastTimerEv = tempv; if (tempv.EventName == "timer") lastTimerEv = tempv;
} }
// Post events // Post events
PostEvent(new EventParams("state_exit", new Object[0], PostEvent(new EventParams("state_exit", new Object[0],
new DetectParams[0])); new DetectParams[0]));
@ -633,11 +637,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
new DetectParams[0])); new DetectParams[0]));
PostEvent(new EventParams("state_entry", new Object[0], PostEvent(new EventParams("state_entry", new Object[0],
new DetectParams[0])); new DetectParams[0]));
// Requeue the timer event after the state changing events // Requeue the timer event after the state changing events
if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv); if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv);
// This will stop events from being queued and processed // This will stop events from being queued and processed
// until the new state is started // until the new state is started
m_StateChangeInProgress = true; m_StateChangeInProgress = true;
}
throw new EventAbortException(); throw new EventAbortException();
} }