Yengine: try fix changing scripts running state if the have long events

0.9.1.0-post-fixes
UbitUmarov 2019-04-01 13:58:41 +01:00
parent 3b63699b9d
commit 7f55db72d2
4 changed files with 96 additions and 23 deletions

View File

@ -1535,15 +1535,38 @@ namespace OpenSim.Region.ScriptEngine.Yengine
*/
public void QueueToStart(XMRInstance inst)
{
if(inst.m_IState != XMRInstState.ONSTARTQ)
if (inst.m_IState != XMRInstState.ONSTARTQ)
throw new Exception("bad state");
lock(m_StartQueue)
lock (m_StartQueue)
m_StartQueue.InsertTail(inst);
WakeUpOne();
}
public void QueueToYield(XMRInstance inst)
{
if (inst.m_IState != XMRInstState.ONYIELDQ)
throw new Exception("bad state");
lock (m_YieldQueue)
m_YieldQueue.InsertTail(inst);
WakeUpOne();
}
public void RemoveFromSleep(XMRInstance inst)
{
lock (m_SleepQueue)
{
if (inst.m_IState != XMRInstState.ONSLEEPQ)
return;
m_SleepQueue.Remove(inst);
inst.m_IState = XMRInstState.REMDFROMSLPQ;
}
}
/**
* @brief A script may be sleeping, in which case we wake it.
*/

View File

@ -363,8 +363,33 @@ namespace OpenSim.Region.ScriptEngine.Yengine
lock(m_QueueLock)
{
m_Running = value;
if(!value)
if(value)
{
if (m_IState == XMRInstState.SUSPENDED && m_SuspendCount == 0)
{
if(eventCode != ScriptEventCode.None)
{
m_IState = XMRInstState.ONYIELDQ;
m_Engine.QueueToYield(this);
}
else if ((m_EventQueue != null) && (m_EventQueue.First != null))
{
m_IState = XMRInstState.ONSTARTQ;
m_Engine.QueueToStart(this);
}
else
m_IState = XMRInstState.IDLE;
}
else if(m_SuspendCount != 0)
m_IState = XMRInstState.IDLE;
}
else
{
if(m_IState == XMRInstState.ONSLEEPQ)
{
m_Engine.RemoveFromSleep(this);
m_IState = XMRInstState.SUSPENDED;
}
EmptyEventQueues();
}
}

View File

@ -80,10 +80,21 @@ namespace OpenSim.Region.ScriptEngine.Yengine
!m_HaveEventHandlers[(int)evc]) // don't bother if we don't have such a handler in any state
return;
// Not running means we ignore any incoming events.
// But queue if still constructing because m_Running is not yet valid.
// Not running means we ignore any incoming events.
// But queue if still constructing because m_Running is not yet valid.
if(!m_Running && !construct)
{
if(m_IState == XMRInstState.SUSPENDED)
{
if(evc == ScriptEventCode.state_entry && m_EventQueue.Count == 0)
{
LinkedListNode<EventParams> llns = new LinkedListNode<EventParams>(evt);
m_EventQueue.AddFirst(llns);
}
}
return;
}
if(m_minEventDelay != 0)
{
@ -250,13 +261,13 @@ namespace OpenSim.Region.ScriptEngine.Yengine
return XMRInstState.SUSPENDED;
}
// Make sure we aren't being migrated in or out and prevent that
// whilst we are in here. If migration has it locked, don't call
// back right away, delay a bit so we don't get in infinite loop.
// Make sure we aren't being migrated in or out and prevent that
// whilst we are in here. If migration has it locked, don't call
// back right away, delay a bit so we don't get in infinite loop.
m_RunOnePhase = "lock m_RunLock";
if(!Monitor.TryEnter(m_RunLock))
{
m_SleepUntil = now.AddMilliseconds(3);
m_SleepUntil = now.AddMilliseconds(15);
m_RunOnePhase = "return was locked";
return XMRInstState.ONSLEEPQ;
}
@ -273,6 +284,12 @@ namespace OpenSim.Region.ScriptEngine.Yengine
return XMRInstState.DISPOSED;
}
if(!m_Running)
{
m_RunOnePhase = "return is not running";
return XMRInstState.SUSPENDED;
}
// Do some more of the last event if it didn't finish.
if(this.eventCode != ScriptEventCode.None)
{
@ -325,10 +342,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine
if(m_EventQueue.First != null)
{
evt = m_EventQueue.First.Value;
if(m_DetachQuantum > 0)
evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
if (m_DetachQuantum > 0)
{
evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName);
if(evc != ScriptEventCode.attach)
{
// This is the case where the attach event
@ -343,8 +359,6 @@ namespace OpenSim.Region.ScriptEngine.Yengine
}
}
m_EventQueue.RemoveFirst();
evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName);
if((int)evc >= 0)
m_EventCounts[(int)evc]--;
}
@ -730,11 +744,14 @@ namespace OpenSim.Region.ScriptEngine.Yengine
case XMRInstState.DISPOSED:
return;
// Some other thread is already resetting it, let it finish.
// Some other thread is already resetting it, let it finish.
case XMRInstState.RESETTING:
return;
case XMRInstState.SUSPENDED:
break;
default:
throw new Exception("bad state");
}
@ -744,17 +761,21 @@ namespace OpenSim.Region.ScriptEngine.Yengine
{
CheckRunLockInvariants(true);
// No other thread should have transitioned it from RESETTING.
if(m_IState != XMRInstState.RESETTING)
throw new Exception("bad state");
// No other thread should have transitioned it from RESETTING.
if (m_IState != XMRInstState.SUSPENDED)
{
if (m_IState != XMRInstState.RESETTING)
throw new Exception("bad state");
// Mark it idle now so it can get queued to process new stuff.
m_IState = XMRInstState.IDLE;
m_IState = XMRInstState.IDLE;
}
// Reset everything and queue up default's start_entry() event.
// Reset everything and queue up default's start_entry() event.
ClearQueue();
ResetLocked("external Reset");
// Mark it idle now so it can get queued to process new stuff.
CheckRunLockInvariants(true);
}
}

View File

@ -166,7 +166,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine
if(inst == null)
break;
if(inst.m_IState != XMRInstState.ONSTARTQ)
if (inst.m_IState == XMRInstState.SUSPENDED)
continue;
if (inst.m_IState != XMRInstState.ONSTARTQ)
throw new Exception("bad state");
RunInstance(inst, tid);
if(m_SuspendScriptThreadFlag || m_Exiting)
@ -187,7 +189,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine
if(inst != null)
{
if(inst.m_IState != XMRInstState.ONYIELDQ)
if (inst.m_IState == XMRInstState.SUSPENDED)
continue;
if (inst.m_IState != XMRInstState.ONYIELDQ)
throw new Exception("bad state");
RunInstance(inst, tid);
continue;