Esempio n. 1
0
 private void TransitionToSynchronized(QState targetState, ref TransitionChain transitionChain)
 {
     //The entire method had been embedded within [MethodImpl(MethodImplOptions.Synchronized)],
     //which is not available in .NET Core, and so a lock is used instead...
     lock (this)
     {
         if (transitionChain != null)
         {
             // We encountered a race condition. The first (non-synchronized) check indicated that the transition chain
             // is null. However, a second threat beat us in getting into this synchronized method and populated
             // the transition chain in the meantime. We can execute the regular method again now.
             TransitionTo(targetState, ref transitionChain);
         }
         else
         {
             // The transition chain is not initialized yet, we need to dynamically retrieve
             // the required transition steps and record them so that we can subsequently simply
             // play them back.
             TransitionChainRecorder recorder = new TransitionChainRecorder();
             TransitionFromSourceToTarget(targetState.GetMethodInfo(), recorder);
             // We pass the recorded transition steps back to the caller:
             transitionChain = recorder.GetRecordedTransitionChain();
         }
     }
 }
Esempio n. 2
0
        private void TransitionDownToTargetState(
            QState targetState,
            ArrayList statesTargetToLCA,
            int indexFirstStateToEnter,
            TransitionChainRecorder recorder)
        {
            // we enter the states in the passed in array in reverse order
            for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--)
            {
                Trigger((QState)statesTargetToLCA[stateIndex], QSignals.Entry, recorder);
            }

            m_MyState = targetState;

            // At last we are ready to initialize the target state.
            // If the specified target state handles init then the effective
            // target state is deeper than the target state specified in
            // the transition.
            while (Trigger(targetState, QSignals.Init, recorder) == null)
            {
                // Initial transition must be one level deep
                Debug.Assert(targetState == GetSuperState(m_MyState));
                targetState = m_MyState;
                Trigger(targetState, QSignals.Entry, recorder);
            }

            if (recorder != null)
            {
                // We always make sure that the last entry in the recorder represents the entry to the target state.
                EnsureLastTransistionStepIsEntryIntoTargetState(targetState, recorder);
                Debug.Assert(recorder.GetRecordedTransitionChain().Length > 0);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Handles the transition from the source state to the target state without the help of a previously
        /// recorded transition chain.
        /// </summary>
        /// <param name="targetState">The <see cref="QState"/> representing the state to transition to.</param>
        /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> or <see langword="null"/></param>
        /// <remarks>
        /// Passing in <see langword="null"/> as the recorder means that we deal with a dynamic transition.
        /// If an actual instance of <see cref="TransitionChainRecorder"/> is passed in then we deal with a static
        /// transition that was not recorded yet. In this case the function will record the transition steps
        /// as they are determined.
        /// </remarks>
        private void TransitionFromSourceToTarget(QState targetState, TransitionChainRecorder recorder)
        {
            ArrayList statesTargetToLCA;
            int       indexFirstStateToEnter;

            ExitUpToLCA(targetState, out statesTargetToLCA, out indexFirstStateToEnter, recorder);
            TransitionDownToTargetState(targetState, statesTargetToLCA, indexFirstStateToEnter, recorder);
        }
Esempio n. 4
0
        /// <summary>
        /// Sends the specified signal to the specified state and (optionally) records the transition
        /// </summary>
        /// <param name="receiverState">The <see cref="QState"/> that represents the state method
        /// to which to send the signal.</param>
        /// <param name="qSignal">The <see cref="QSignals"/> to send.</param>
        /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> if the transition
        /// is to be recorded; <see langword="null"/> otherwise.</param>
        /// <returns>The <see cref="QState"/> returned by the state that recieved the signal.</returns>
        /// <remarks>
        /// Even if a recorder is specified, the transition will only be recorded if the state
        /// <see paramref="receiverState"/> actually handled it.
        /// This function is used to record the transition chain for a static transition that is executed
        /// the first time.
        /// </remarks>
        private QState Trigger(QState receiverState, string qSignal, TransitionChainRecorder recorder)
        {
            QState state = Trigger(receiverState, qSignal);

            if ((state == null) && (recorder != null))
            {
                // The receiverState handled the event
                recorder.Record(receiverState, qSignal);
            }
            return(state);
        }
Esempio n. 5
0
        /// <summary>
        /// Sends the specified signal to the specified state and (optionally) records the transition
        /// </summary>
        /// <param name="receiverStateMethod">The <see cref="MethodInfo"/> that represents the state method
        /// to which to send the signal.</param>
        /// <param name="qSignal">The <see cref="QSignals"/> to send.</param>
        /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> if the transition
        /// is to be recorded; <see langword="null"/> otherwise.</param>
        /// <returns>The <see cref="QState"/> returned by the state that recieved the signal.</returns>
        /// <remarks>
        /// Even if a recorder is specified, the transition will only be recorded if the state
        /// <see paramref="receiverStateMethod"/> actually handled it.
        /// This function is used to record the transition chain for a static transition that is executed
        /// the first time.
        /// </remarks>
        private MethodInfo Trigger(MethodInfo receiverStateMethod, QSignals qSignal, TransitionChainRecorder recorder)
        {
            MethodInfo stateMethod = Trigger(receiverStateMethod, qSignal);

            if ((stateMethod == null) && (recorder != null))
            {
                // The receiverState handled the event
                recorder.Record(receiverStateMethod, qSignal);
            }
            return(stateMethod);
        }
Esempio n. 6
0
 private void TransitionToSynchronized(QState targetState, ref TransitionChain transitionChain)
 {
     if (transitionChain != null)
     {
         // We encountered a race condition. The first (non-synchronized) check indicated that the transition chain
         // is null. However, a second threat beat us in getting into this synchronized method and populated
         // the transition chain in the meantime. We can execute the regular method again now.
         TransitionTo(targetState, ref transitionChain);
     }
     else
     {
         // The transition chain is not initialized yet, we need to dynamically retrieve
         // the required transition steps and record them so that we can subsequently simply
         // play them back.
         TransitionChainRecorder recorder = new TransitionChainRecorder();
         TransitionFromSourceToTarget(targetState, recorder);
         // We pass the recorded transition steps back to the caller:
         transitionChain = recorder.GetRecordedTransitionChain();
     }
 }
Esempio n. 7
0
 private void EnsureLastTransistionStepIsEntryIntoTargetState(
     QState targetState,
     TransitionChainRecorder recorder)
 {
     if (recorder.GetRecordedTransitionChain().Length == 0)
     {
         // Nothing recorded so far
         RecordEntryIntoTargetState(targetState, recorder);
         return;
     }
     else
     {
         // We need to test whether the last recorded transition step is the entry into the target state
         TransitionChain transitionChain    = recorder.GetRecordedTransitionChain();
         TransitionStep  lastTransitionStep = transitionChain[transitionChain.Length - 1];
         if (lastTransitionStep.State != targetState ||
             lastTransitionStep.QSignal != QSignals.Entry)
         {
             RecordEntryIntoTargetState(targetState, recorder);
             return;
         }
     }
 }
Esempio n. 8
0
        /// <summary>
        /// Determines the transition chain between the target state and the LCA (Least Common Ancestor)
        /// and exits up to LCA while doing so.
        /// </summary>
        /// <param name="targetStateMethod">The target state method of the transition.</param>
        /// <param name="statesTargetToLCA">An <see cref="ArrayList"/> that holds (in reverse order) the states
        /// that need to be entered on the way down to the target state.
        /// Note: The index of the first state that needs to be entered is returned in
        /// <see paramref="indexFirstStateToEnter"/>.</param>
        /// <param name="indexFirstStateToEnter">Returns the index in the array <see cparamref="statesTargetToLCA"/>
        /// that specifies the first state that needs to be entered on the way down to the target state.</param>
        /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> if the transition chain
        /// should be recorded; <see langword="null"/> otherwise.</param>
        private void ExitUpToLCA(
            QState targetState,
            out ArrayList statesTargetToLCA,
            out int indexFirstStateToEnter,
            TransitionChainRecorder recorder)
        {
            statesTargetToLCA = new ArrayList();
            statesTargetToLCA.Add(targetState);
            indexFirstStateToEnter = 0;

            // (a) check my source state == target state (transition to self)
            if (m_MySourceState == targetState)
            {
                Trigger(m_MySourceState, QSignals.Exit, recorder);
                return;
            }

            // (b) check my source state == super state of the target state
            QState targetSuperState = GetSuperState(targetState);

            //Debug.WriteLine(targetSuperState.Name);
            if (m_MySourceState == targetSuperState)
            {
                return;
            }

            // (c) check super state of my source state == super state of target state
            // (most common)
            QState sourceSuperState = GetSuperState(m_MySourceState);

            if (sourceSuperState == targetSuperState)
            {
                Trigger(m_MySourceState, QSignals.Exit, recorder);
                return;
            }

            // (d) check super state of my source state == target
            if (sourceSuperState == targetState)
            {
                Trigger(m_MySourceState, QSignals.Exit, recorder);
                indexFirstStateToEnter = -1;                 // we don't enter the LCA
                return;
            }

            // (e) check rest of my source = super state of super state ... of target state hierarchy
            statesTargetToLCA.Add(targetSuperState);
            indexFirstStateToEnter++;
            for (QState state = GetSuperState(targetSuperState);
                 state != null; state = GetSuperState(state))
            {
                if (m_MySourceState == state)
                {
                    return;
                }

                statesTargetToLCA.Add(state);
                indexFirstStateToEnter++;
            }

            // For both remaining cases we need to exit the source state
            Trigger(m_MySourceState, QSignals.Exit, recorder);

            // (f) check rest of super state of my source state ==
            //     super state of super state of ... target state
            // The array list is currently filled with all the states
            // from the target state up to the top state
            for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--)
            {
                if (sourceSuperState == (QState)statesTargetToLCA[stateIndex])
                {
                    indexFirstStateToEnter = stateIndex - 1;
                    // Note that we do not include the LCA state itself;
                    // i.e., we do not enter the LCA
                    return;
                }
            }

            // (g) check each super state of super state ... of my source state ==
            //     super state of super state of ... target state
            for (QState state = sourceSuperState;
                 state != null; state = GetSuperState(state))
            {
                for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--)
                {
                    if (state == (QState)statesTargetToLCA[stateIndex])
                    {
                        indexFirstStateToEnter = stateIndex - 1;
                        // Note that we do not include the LCA state itself;
                        // i.e., we do not enter the LCA
                        return;
                    }
                }
                Trigger(state, QSignals.Exit, recorder);
            }

            // We should never get here
            throw new ApplicationException("Mal formed Hierarchical State Machine");
        }
Esempio n. 9
0
 private void RecordEntryIntoTargetState(
     MethodInfo targetStateMethod,
     TransitionChainRecorder recorder)
 {
     recorder.Record(targetStateMethod, QSignals.Entry);
 }
Esempio n. 10
0
        /// <summary>
        /// Determines the transition chain between the target state and the LCA (Least Common Ancestor)
        /// and exits up to LCA while doing so.
        /// </summary>
        /// <param name="targetStateMethod">The target state method of the transition.</param>
        /// <param name="statesTargetToLCA">An <see cref="ArrayList"/> that holds (in reverse order) the states
        /// that need to be entered on the way down to the target state.
        /// Note: The index of the first state that needs to be entered is returned in 
        /// <see paramref="indexFirstStateToEnter"/>.</param>
        /// <param name="indexFirstStateToEnter">Returns the index in the array <see cparamref="statesTargetToLCA"/>
        /// that specifies the first state that needs to be entered on the way down to the target state.</param>
        /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> if the transition chain
        /// should be recorded; <see langword="null"/> otherwise.</param>
        private void ExitUpToLCA(
            MethodInfo targetStateMethod,
            out ArrayList statesTargetToLCA,
            out int indexFirstStateToEnter,
            TransitionChainRecorder recorder)
        {
            statesTargetToLCA = new ArrayList();
            statesTargetToLCA.Add(targetStateMethod);
            indexFirstStateToEnter = 0;

            // (a) check my source state == target state (transition to self)
            if(m_MySourceStateMethod == targetStateMethod)
            {
                Trigger(m_MySourceStateMethod, QSignals.Exit, recorder);
                return;
            }

            // (b) check my source state == super state of the target state
            MethodInfo targetSuperStateMethod = GetSuperStateMethod(targetStateMethod);
            //Debug.WriteLine(targetSuperStateMethod.Name);
            if(m_MySourceStateMethod == targetSuperStateMethod)
            {
                return;
            }

            // (c) check super state of my source state == super state of target state
            // (most common)
            MethodInfo sourceSuperStateMethod = GetSuperStateMethod(m_MySourceStateMethod);
            if(sourceSuperStateMethod == targetSuperStateMethod)
            {
                Trigger(m_MySourceStateMethod, QSignals.Exit, recorder);
                return;
            }

            // (d) check super state of my source state == target
            if (sourceSuperStateMethod == targetStateMethod)
            {
                Trigger(m_MySourceStateMethod, QSignals.Exit, recorder);
                indexFirstStateToEnter = -1; // we don't enter the LCA
                return;
            }

            // (e) check rest of my source = super state of super state ... of target state hierarchy
            statesTargetToLCA.Add(targetSuperStateMethod);
            indexFirstStateToEnter++;
            for (MethodInfo stateMethod = GetSuperStateMethod(targetSuperStateMethod);
                stateMethod != null; stateMethod = GetSuperStateMethod(stateMethod))
            {
                if (m_MySourceStateMethod == stateMethod)
                {
                    return;
                }

                statesTargetToLCA.Add(stateMethod);
                indexFirstStateToEnter++;
            }

            // For both remaining cases we need to exit the source state
            Trigger(m_MySourceStateMethod, QSignals.Exit, recorder);

            // (f) check rest of super state of my source state ==
            //     super state of super state of ... target state
            // The array list is currently filled with all the states
            // from the target state up to the top state
            for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--)
            {
                if (sourceSuperStateMethod == (MethodInfo)statesTargetToLCA[stateIndex])
                {
                    indexFirstStateToEnter = stateIndex - 1;
                    // Note that we do not include the LCA state itself;
                    // i.e., we do not enter the LCA
                    return;
                }
            }

            // (g) check each super state of super state ... of my source state ==
            //     super state of super state of ... target state
            for (MethodInfo stateMethod = sourceSuperStateMethod;
                stateMethod != null; stateMethod = GetSuperStateMethod(stateMethod))
            {
                for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--)
                {
                    if (stateMethod == (MethodInfo)statesTargetToLCA[stateIndex])
                    {
                        indexFirstStateToEnter = stateIndex - 1;
                        // Note that we do not include the LCA state itself;
                        // i.e., we do not enter the LCA
                        return;
                    }
                }
                Trigger(stateMethod, QSignals.Exit, recorder);
            }

            // We should never get here
            throw new ApplicationException("Mal formed Hierarchical State Machine");
        }
Esempio n. 11
0
 /// <summary>
 /// Sends the specified signal to the specified state and (optionally) records the transition
 /// </summary>
 /// <param name="receiverStateMethod">The <see cref="MethodInfo"/> that represents the state method
 /// to which to send the signal.</param>
 /// <param name="qSignal">The <see cref="QSignals"/> to send.</param>
 /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> if the transition
 /// is to be recorded; <see langword="null"/> otherwise.</param>
 /// <returns>The <see cref="QState"/> returned by the state that recieved the signal.</returns>
 /// <remarks>
 /// Even if a recorder is specified, the transition will only be recorded if the state 
 /// <see paramref="receiverStateMethod"/> actually handled it.
 /// This function is used to record the transition chain for a static transition that is executed
 /// the first time. 
 /// </remarks>
 private MethodInfo Trigger(MethodInfo receiverStateMethod, string qSignal, TransitionChainRecorder recorder)
 {
     MethodInfo stateMethod = Trigger(receiverStateMethod, qSignal);
     if ((stateMethod == null) && (recorder != null))
     {
         // The receiverState handled the event
         recorder.Record(receiverStateMethod, qSignal);
     }
     return stateMethod;
 }
Esempio n. 12
0
 private void TransitionToSynchronized(QState targetState, ref TransitionChain transitionChain)
 {
     if (transitionChain != null)
     {
         // We encountered a race condition. The first (non-synchronized) check indicated that the transition chain
         // is null. However, a second threat beat us in getting into this synchronized method and populated
         // the transition chain in the meantime. We can execute the regular method again now.
         TransitionTo(targetState, ref transitionChain);
     }
     else
     {
         // The transition chain is not initialized yet, we need to dynamically retrieve
         // the required transition steps and record them so that we can subsequently simply
         // play them back.
         TransitionChainRecorder recorder = new TransitionChainRecorder();
         TransitionFromSourceToTarget(targetState.Method, recorder);
         // We pass the recorded transition steps back to the caller:
         transitionChain = recorder.GetRecordedTransitionChain();
     }
 }
Esempio n. 13
0
 /// <summary>
 /// Handles the transition from the source state to the target state without the help of a previously
 /// recorded transition chain.
 /// </summary>
 /// <param name="targetStateMethod">The <see cref="MethodInfo"/> representing the state method to transition to.</param>
 /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> or <see langword="null"/></param>
 /// <remarks>
 /// Passing in <see langword="null"/> as the recorder means that we deal with a dynamic transition.
 /// If an actual instance of <see cref="TransitionChainRecorder"/> is passed in then we deal with a static
 /// transition that was not recorded yet. In this case the function will record the transition steps
 /// as they are determined.
 /// </remarks>
 private void TransitionFromSourceToTarget(MethodInfo targetStateMethod, TransitionChainRecorder recorder)
 {
     ArrayList statesTargetToLCA;
     int indexFirstStateToEnter;
     ExitUpToLCA(targetStateMethod, out statesTargetToLCA, out indexFirstStateToEnter, recorder);
     TransitionDownToTargetState(targetStateMethod, statesTargetToLCA, indexFirstStateToEnter, recorder);
 }
Esempio n. 14
0
        private void TransitionDownToTargetState(
            MethodInfo targetStateMethod,
            ArrayList statesTargetToLCA,
            int indexFirstStateToEnter,
            TransitionChainRecorder recorder)
        {
            // we enter the states in the passed in array in reverse order
            for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--)
            {
                Trigger((MethodInfo)statesTargetToLCA[stateIndex], QSignals.Entry, recorder);
            }

            m_MyStateMethod = targetStateMethod;

            // At last we are ready to initialize the target state.
            // If the specified target state handles init then the effective
            // target state is deeper than the target state specified in
            // the transition.
            while (Trigger(targetStateMethod, QSignals.Init, recorder) == null)
            {
                // Initial transition must be one level deep
                Debug.Assert(targetStateMethod == GetSuperStateMethod(m_MyStateMethod));
                targetStateMethod = m_MyStateMethod;
                Trigger(targetStateMethod, QSignals.Entry, recorder);
            }

            if (recorder != null)
            {
                // We always make sure that the last entry in the recorder represents the entry to the target state.
                EnsureLastTransistionStepIsEntryIntoTargetState(targetStateMethod, recorder);
                Debug.Assert(recorder.GetRecordedTransitionChain().Length > 0);
            }
        }
Esempio n. 15
0
 private void RecordEntryIntoTargetState(
     MethodInfo targetStateMethod,
     TransitionChainRecorder recorder)
 {
     recorder.Record(targetStateMethod, QSignals.Entry);
 }
Esempio n. 16
0
 private void RecordEntryIntoTargetState(
     QState targetState,
     TransitionChainRecorder recorder)
 {
     recorder.Record(targetState, QSignals.Entry);
 }
Esempio n. 17
0
 private void EnsureLastTransistionStepIsEntryIntoTargetState(
     MethodInfo targetStateMethod,
     TransitionChainRecorder recorder)
 {
     if (recorder.GetRecordedTransitionChain().Length == 0)
     {
         // Nothing recorded so far
         RecordEntryIntoTargetState(targetStateMethod, recorder);
         return;
     }
     else
     {
         // We need to test whether the last recorded transition step is the entry into the target state
         TransitionChain transitionChain = recorder.GetRecordedTransitionChain();
         TransitionStep lastTransitionStep = transitionChain[transitionChain.Length - 1];
         if (lastTransitionStep.StateMethod != targetStateMethod ||
             lastTransitionStep.QSignal != QSignals.Entry)
         {
             RecordEntryIntoTargetState(targetStateMethod, recorder);
             return;
         }
     }
 }