You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
8.7 KiB
259 lines
8.7 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
// File: statemachinebase.cpp
|
|
//
|
|
// Description:
|
|
// Implementation of CStateMachineBaseClass
|
|
//
|
|
// Author: Mike Swafford (MikeSwa)
|
|
//
|
|
// History:
|
|
// 12/11/2000 - MikeSwa Created
|
|
//
|
|
// Copyright (C) 2000 Microsoft Corporation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#include "aqprecmp.h"
|
|
#include "statemachinebase.h"
|
|
|
|
//---[ CStateMachineBase::CStateMachineBase ]-----------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// CStateMachineBase constructor
|
|
// Parameters:
|
|
// - dwInitialState Initial state to set state
|
|
// machine to
|
|
// dwStateMachineSignature Signature of the state machine
|
|
// subclass
|
|
// Returns:
|
|
// -
|
|
// History:
|
|
// 6/5/2000 - t-toddc Created
|
|
//
|
|
//------------------------------------------------------------------
|
|
CStateMachineBase::CStateMachineBase(DWORD dwInitialState,
|
|
DWORD dwStateMachineSignature) :
|
|
m_dwSignature(STATE_MACHINE_BASE_SIG),
|
|
m_dwStateMachineSignature(dwStateMachineSignature),
|
|
m_dwCurrentState(dwInitialState)
|
|
{
|
|
};
|
|
|
|
//---[ CStateMachineBase::dwGetCurrentState ]----------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// returns the current state of the state machine
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// - current state
|
|
// History:
|
|
// 6/5/2000 - t-toddc Created
|
|
//
|
|
//------------------------------------------------------------------
|
|
DWORD CStateMachineBase::dwGetCurrentState()
|
|
{
|
|
return m_dwCurrentState;
|
|
}
|
|
|
|
//---[ CStateMachineBase::dwGetNextState ]-------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// sets the next state based on current state and input action.
|
|
// Uses InterlockedCompareExchange to make sure that the state
|
|
// transition is thread-safe.
|
|
// Parameters:
|
|
// - dwAction the current action causing the state transition
|
|
// Returns:
|
|
// - the resultant state based on the current state and
|
|
// input action
|
|
// History:
|
|
// 6/5/2000 - t-toddc Created
|
|
//
|
|
//------------------------------------------------------------------
|
|
DWORD CStateMachineBase::dwGetNextState(DWORD dwAction)
|
|
{
|
|
TraceFunctEnter("CStateMachineBase::dwGetNextState");
|
|
|
|
DWORD dwCurrentState;
|
|
DWORD dwNextState;
|
|
|
|
do
|
|
{
|
|
dwCurrentState = m_dwCurrentState;
|
|
dwNextState = dwCalcStateFromStateAndAction(dwCurrentState, dwAction);
|
|
if (dwCurrentState == dwNextState)
|
|
break; // no work to be done
|
|
} while (InterlockedCompareExchange((LPLONG) &m_dwCurrentState,
|
|
(LONG) dwNextState,
|
|
(LONG) dwCurrentState)!= (LONG) dwCurrentState);
|
|
DebugTrace((LPARAM) this,
|
|
"CStateMachineBase state transition: %X->%X",
|
|
dwCurrentState,
|
|
dwNextState);
|
|
TraceFunctLeave();
|
|
return dwNextState;
|
|
}
|
|
|
|
//---[ CStateMachineBase::dwCalcStateFromStateAndAction ]------------
|
|
//
|
|
//
|
|
// Description:
|
|
// iterates through the state transition table to find the
|
|
// next state associated with the current state and input action
|
|
// Parameters:
|
|
// - dwStartState start state for this transition
|
|
// dwAction the action associated with this transition
|
|
// Returns:
|
|
// - the resultant state associated with current state and action
|
|
// History:
|
|
// 6/5/2000 - t-toddc Created
|
|
//
|
|
//
|
|
//------------------------------------------------------------------
|
|
DWORD CStateMachineBase::dwCalcStateFromStateAndAction(DWORD dwStartState, DWORD dwAction)
|
|
{
|
|
TraceFunctEnter("CStateMachineBase::dwCalcStateFromStateAndAction");
|
|
// if the action is unknown to state table, return start state
|
|
DWORD dwNextState = dwStartState;
|
|
DWORD i;
|
|
const STATE_TRANSITION* pTransitionTable;
|
|
DWORD dwNumTransitions;
|
|
BOOL fFoundTransition = FALSE;
|
|
// obtain the transition table
|
|
getTransitionTable(&pTransitionTable, &dwNumTransitions);
|
|
|
|
// find the new state
|
|
for(i=0; i < dwNumTransitions; i++)
|
|
{
|
|
if (pTransitionTable[i].dwCurrentState == dwStartState &&
|
|
pTransitionTable[i].dwAction == dwAction)
|
|
{
|
|
dwNextState = pTransitionTable[i].dwNextState;
|
|
fFoundTransition = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(fFoundTransition && "action unknown to state table");
|
|
if (!fFoundTransition)
|
|
DebugTrace((LPARAM) this,"action %X unknown to state tabe", dwAction);
|
|
|
|
TraceFunctLeave();
|
|
return dwNextState;
|
|
}
|
|
|
|
//---[ CStateMachineBase::fValidateStateTable ]---------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// loops through all transitions and checks that
|
|
// a) all possible states are start states
|
|
// b) for every state, every possible action yields another state
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// - true/false if state table is valid/invalid
|
|
// History:
|
|
// 6/5/2000 - t-toddc Created
|
|
//
|
|
//------------------------------------------------------------------
|
|
BOOL CStateMachineBase::fValidateStateTable()
|
|
{
|
|
TraceFunctEnter("CStateMachineBase::fValidateStateTable");
|
|
|
|
DWORD i, j, k; // iterators
|
|
DWORD dwEndState;
|
|
DWORD dwAction;
|
|
DWORD dwCurrentState;
|
|
BOOL fFoundEndStateAsStartState = false;
|
|
BOOL fActionSupportedByEveryState = false;
|
|
const STATE_TRANSITION* pTransitionTable;
|
|
DWORD dwNumTransitions;
|
|
BOOL fRetVal = false;
|
|
|
|
// obtain the transition table
|
|
getTransitionTable(&pTransitionTable, &dwNumTransitions);
|
|
|
|
for(i = 0; i < dwNumTransitions; i++)
|
|
{
|
|
// initialize booleans within loop
|
|
fFoundEndStateAsStartState = false;
|
|
// grab the current action
|
|
dwAction = pTransitionTable[i].dwAction;
|
|
// grab the current end state
|
|
dwEndState = pTransitionTable[i].dwNextState;
|
|
|
|
// loop over all transitions
|
|
for (j = 0; j < dwNumTransitions; j++)
|
|
{
|
|
// check that the current end state is a start state
|
|
if (pTransitionTable[j].dwCurrentState == dwEndState)
|
|
{
|
|
fFoundEndStateAsStartState = true;
|
|
}
|
|
|
|
// check that every action is supported by every state
|
|
fActionSupportedByEveryState = false;
|
|
dwCurrentState = pTransitionTable[j].dwCurrentState;
|
|
// the current action might not be in this particular transition,
|
|
// but it must be in a transition with this dwCurrentState as the start state
|
|
if (pTransitionTable[j].dwAction != dwAction)
|
|
{
|
|
// loop over all transitions again to guarantee the above.
|
|
for(k = 0; k < dwNumTransitions; k++)
|
|
{
|
|
// there must exist a state transition with the current state
|
|
// from above and the given action
|
|
if (pTransitionTable[k].dwAction == dwAction &&
|
|
pTransitionTable[k].dwCurrentState == dwCurrentState)
|
|
{
|
|
fActionSupportedByEveryState = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fActionSupportedByEveryState = true;
|
|
}
|
|
|
|
// bail on false if the current action is not supported by every state
|
|
ASSERT(fActionSupportedByEveryState &&
|
|
"Invalid state table: action not supported by every state");
|
|
if (!fActionSupportedByEveryState)
|
|
{
|
|
fRetVal = false;
|
|
DebugTrace((LPARAM) this,
|
|
"Invalid state table: action not supported by every state");
|
|
goto Cleanup;
|
|
}
|
|
// break out of inner loop if the current end state has been found
|
|
// as a start state
|
|
if (fFoundEndStateAsStartState)
|
|
break;
|
|
}
|
|
|
|
// bail on false if an end state is not also a start state
|
|
ASSERT(fFoundEndStateAsStartState &&
|
|
"Invalid state table: an end state is not also a start state");
|
|
if (!fFoundEndStateAsStartState)
|
|
{
|
|
fRetVal = false;
|
|
DebugTrace((LPARAM) this,
|
|
"Invalid state table: an end state is not also a start state");
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
// if it makes it this far, it is undoubtedly valid.
|
|
fRetVal = true;
|
|
|
|
Cleanup:
|
|
TraceFunctLeave();
|
|
return fRetVal;
|
|
}
|