/** * @brief A script instance was just removed from the Start or Yield Queue. * So run it for a little bit then stick in whatever queue it should go in. */ private void RunInstance(XMRInstance inst, int tid) { m_LastRanAt = DateTime.UtcNow; m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds; inst.m_IState = XMRInstState.RUNNING; lock (m_WakeUpLock) { m_RunningInstances[tid] = inst; } XMRInstState newIState = inst.RunOne(); lock (m_WakeUpLock) { m_RunningInstances[tid] = null; } HandleNewIState(inst, newIState); m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds; }
/** * @brief The user clicked the Reset Script button. * We want to reset the script to a never-has-ever-run-before state. */ public void Reset() { checkstate: XMRInstState iState = m_IState; switch (iState) { // If it's really being constructed now, that's about as reset as we get. case XMRInstState.CONSTRUCT: return; // If it's idle, that means it is ready to receive a new event. // So we lock the event queue to prevent another thread from taking // it out of idle, verify that it is still in idle then transition // it to resetting so no other thread will touch it. case XMRInstState.IDLE: lock (m_QueueLock) { if (m_IState == XMRInstState.IDLE) { m_IState = XMRInstState.RESETTING; break; } } goto checkstate; // If it's on the start queue, that means it is about to dequeue an // event and start processing it. So we lock the start queue so it // can't be started and transition it to resetting so no other thread // will touch it. case XMRInstState.ONSTARTQ: lock (m_Engine.m_StartQueue) { if (m_IState == XMRInstState.ONSTARTQ) { m_Engine.m_StartQueue.Remove(this); m_IState = XMRInstState.RESETTING; break; } } goto checkstate; // If it's running, tell CheckRun() to suspend the thread then go back // to see what it got transitioned to. case XMRInstState.RUNNING: suspendOnCheckRunHold = true; lock (m_QueueLock) { } goto checkstate; // If it's sleeping, remove it from sleep queue and transition it to // resetting so no other thread will touch it. case XMRInstState.ONSLEEPQ: lock (m_Engine.m_SleepQueue) { if (m_IState == XMRInstState.ONSLEEPQ) { m_Engine.m_SleepQueue.Remove(this); m_IState = XMRInstState.RESETTING; break; } } goto checkstate; // It was just removed from the sleep queue and is about to be put // on the yield queue (ie, is being woken up). // Let that thread complete transition and try again. case XMRInstState.REMDFROMSLPQ: Sleep(10); goto checkstate; // If it's yielding, remove it from yield queue and transition it to // resetting so no other thread will touch it. case XMRInstState.ONYIELDQ: lock (m_Engine.m_YieldQueue) { if (m_IState == XMRInstState.ONYIELDQ) { m_Engine.m_YieldQueue.Remove(this); m_IState = XMRInstState.RESETTING; break; } } goto checkstate; // If it just finished running something, let that thread transition it // to its next state then check again. case XMRInstState.FINISHED: Sleep(10); goto checkstate; // If it's disposed, that's about as reset as it gets. case XMRInstState.DISPOSED: return; // Some other thread is already resetting it, let it finish. case XMRInstState.RESETTING: return; default: throw new Exception("bad state"); } // This thread transitioned the instance to RESETTING so reset it. lock (m_RunLock) { CheckRunLockInvariants(true); // No other thread should have transitioned it from RESETTING. 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; // Reset everything and queue up default's start_entry() event. ClearQueue(); ResetLocked("external Reset"); CheckRunLockInvariants(true); } }