Example #1
0
        /// <summary>
        /// Atomically transitions <see cref="State" /> to <paramref name="targetState" />.
        /// The current state must not change during the attempted transition (i.e., synchronization may be required).
        /// If provided, <paramref name="onCommit"/> is called upon committing to transition to the next state but
        /// before the state could possibly transition further.
        /// </summary>
        /// <remarks>
        /// This method is effectively not thread safe, since one must somehow know that a transition to
        /// <paramref name="targetState" /> is valid
        /// and that the current state will not change during this call (e.g. via some collaborating lock).
        /// </remarks>
        /// <returns>The prior pip state</returns>
        public PipState Transition(PipState targetState, PipType pipType, Action <PipState, PipState, PipType> onCommit = null)
        {
            // This Requires is Static (not at runtime) so we avoid loading State twice (it can change behind our backs).
            // Below we do a final (authoritative) load of State and then runtime-verify a valid transition.
            Contract.RequiresDebug(State.CanTransitionTo(targetState));
            Contract.Requires(pipType < PipType.Max || onCommit == null);

            PipState presentState = State;

            if (!State.CanTransitionTo(targetState))
            {
                Contract.Assume(false, I($"Transition failure (not a valid transition): {presentState:G} -> {targetState:G}"));
            }

            Contract.Assume(((int)presentState & PreCommitStateBit) == 0);
            bool transitioned = TryTransitionInternal(presentState, targetState, pipType, onCommit);

            if (!transitioned)
            {
                Contract.Assume(
                    false,
                    I($"Failed to transition a pip from {presentState:G} to {targetState:G} due to an unexpected intervening state change (current state is now {State:G})"));
            }

            return(presentState);
        }
Example #2
0
        /// <summary>
        /// Atomically transitions <see cref="State" /> from <paramref name="assumedPresentState" /> to
        /// <paramref name="targetState" />.
        /// Returns a bool indicating if the transition succeeded (if false, the <paramref name="assumedPresentState" /> was
        /// mismatched with the current state).
        /// If provided, <paramref name="onCommit"/> is called upon committing to transition to the next state but
        /// before the state could possibly transition further.
        /// </summary>
        /// <remarks>
        /// This method is thread safe.
        /// </remarks>
        public bool TryTransition(PipState assumedPresentState, PipState targetState, PipType pipType = PipType.Max, Action <PipState, PipState, PipType> onCommit = null)
        {
            Contract.Requires(assumedPresentState.CanTransitionTo(targetState));
            Contract.Requires(((int)assumedPresentState & PreCommitStateBit) == 0, "PipState values should have the high bit cleared");
            Contract.Requires(pipType < PipType.Max || onCommit == null);

            return(TryTransitionInternal(assumedPresentState, targetState, pipType, onCommit));
        }