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,25 +619,32 @@ 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;
while (EventQueue.Count > 0)
lock (EventQueue)
{ {
EventParams tempv = (EventParams)EventQueue.Dequeue(); // Remove all queued events, remembering the last timer event
if (tempv.EventName == "timer") lastTimerEv = tempv; while (EventQueue.Count > 0)
{
EventParams tempv = (EventParams)EventQueue.Dequeue();
if (tempv.EventName == "timer") lastTimerEv = tempv;
}
// Post events
PostEvent(new EventParams("state_exit", new Object[0],
new DetectParams[0]));
PostEvent(new EventParams("state", new Object[] { state },
new DetectParams[0]));
PostEvent(new EventParams("state_entry", new Object[0],
new DetectParams[0]));
// Requeue the timer event after the state changing events
if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv);
// This will stop events from being queued and processed
// until the new state is started
m_StateChangeInProgress = true;
} }
// Post events
PostEvent(new EventParams("state_exit", new Object[0],
new DetectParams[0]));
PostEvent(new EventParams("state", new Object[] { state },
new DetectParams[0]));
PostEvent(new EventParams("state_entry", new Object[0],
new DetectParams[0]));
// Requeue the timer event after the state changing events
if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv);
// This will stop events from being queued and processed
// until the new state is started
m_StateChangeInProgress = true;
throw new EventAbortException(); throw new EventAbortException();
} }