Leaked source code of windows server 2003
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

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: statemachinebase.cpp
  5. //
  6. // Description:
  7. // Implementation of CStateMachineBaseClass
  8. //
  9. // Author: Mike Swafford (MikeSwa)
  10. //
  11. // History:
  12. // 12/11/2000 - MikeSwa Created
  13. //
  14. // Copyright (C) 2000 Microsoft Corporation
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include "aqprecmp.h"
  18. #include "statemachinebase.h"
  19. //---[ CStateMachineBase::CStateMachineBase ]-----------------------
  20. //
  21. //
  22. // Description:
  23. // CStateMachineBase constructor
  24. // Parameters:
  25. // - dwInitialState Initial state to set state
  26. // machine to
  27. // dwStateMachineSignature Signature of the state machine
  28. // subclass
  29. // Returns:
  30. // -
  31. // History:
  32. // 6/5/2000 - t-toddc Created
  33. //
  34. //------------------------------------------------------------------
  35. CStateMachineBase::CStateMachineBase(DWORD dwInitialState,
  36. DWORD dwStateMachineSignature) :
  37. m_dwSignature(STATE_MACHINE_BASE_SIG),
  38. m_dwStateMachineSignature(dwStateMachineSignature),
  39. m_dwCurrentState(dwInitialState)
  40. {
  41. };
  42. //---[ CStateMachineBase::dwGetCurrentState ]----------------------
  43. //
  44. //
  45. // Description:
  46. // returns the current state of the state machine
  47. // Parameters:
  48. // -
  49. // Returns:
  50. // - current state
  51. // History:
  52. // 6/5/2000 - t-toddc Created
  53. //
  54. //------------------------------------------------------------------
  55. DWORD CStateMachineBase::dwGetCurrentState()
  56. {
  57. return m_dwCurrentState;
  58. }
  59. //---[ CStateMachineBase::dwGetNextState ]-------------------------
  60. //
  61. //
  62. // Description:
  63. // sets the next state based on current state and input action.
  64. // Uses InterlockedCompareExchange to make sure that the state
  65. // transition is thread-safe.
  66. // Parameters:
  67. // - dwAction the current action causing the state transition
  68. // Returns:
  69. // - the resultant state based on the current state and
  70. // input action
  71. // History:
  72. // 6/5/2000 - t-toddc Created
  73. //
  74. //------------------------------------------------------------------
  75. DWORD CStateMachineBase::dwGetNextState(DWORD dwAction)
  76. {
  77. TraceFunctEnter("CStateMachineBase::dwGetNextState");
  78. DWORD dwCurrentState;
  79. DWORD dwNextState;
  80. do
  81. {
  82. dwCurrentState = m_dwCurrentState;
  83. dwNextState = dwCalcStateFromStateAndAction(dwCurrentState, dwAction);
  84. if (dwCurrentState == dwNextState)
  85. break; // no work to be done
  86. } while (InterlockedCompareExchange((LPLONG) &m_dwCurrentState,
  87. (LONG) dwNextState,
  88. (LONG) dwCurrentState)!= (LONG) dwCurrentState);
  89. DebugTrace((LPARAM) this,
  90. "CStateMachineBase state transition: %X->%X",
  91. dwCurrentState,
  92. dwNextState);
  93. TraceFunctLeave();
  94. return dwNextState;
  95. }
  96. //---[ CStateMachineBase::dwCalcStateFromStateAndAction ]------------
  97. //
  98. //
  99. // Description:
  100. // iterates through the state transition table to find the
  101. // next state associated with the current state and input action
  102. // Parameters:
  103. // - dwStartState start state for this transition
  104. // dwAction the action associated with this transition
  105. // Returns:
  106. // - the resultant state associated with current state and action
  107. // History:
  108. // 6/5/2000 - t-toddc Created
  109. //
  110. //
  111. //------------------------------------------------------------------
  112. DWORD CStateMachineBase::dwCalcStateFromStateAndAction(DWORD dwStartState, DWORD dwAction)
  113. {
  114. TraceFunctEnter("CStateMachineBase::dwCalcStateFromStateAndAction");
  115. // if the action is unknown to state table, return start state
  116. DWORD dwNextState = dwStartState;
  117. DWORD i;
  118. const STATE_TRANSITION* pTransitionTable;
  119. DWORD dwNumTransitions;
  120. BOOL fFoundTransition = FALSE;
  121. // obtain the transition table
  122. getTransitionTable(&pTransitionTable, &dwNumTransitions);
  123. // find the new state
  124. for(i=0; i < dwNumTransitions; i++)
  125. {
  126. if (pTransitionTable[i].dwCurrentState == dwStartState &&
  127. pTransitionTable[i].dwAction == dwAction)
  128. {
  129. dwNextState = pTransitionTable[i].dwNextState;
  130. fFoundTransition = TRUE;
  131. break;
  132. }
  133. }
  134. ASSERT(fFoundTransition && "action unknown to state table");
  135. if (!fFoundTransition)
  136. DebugTrace((LPARAM) this,"action %X unknown to state tabe", dwAction);
  137. TraceFunctLeave();
  138. return dwNextState;
  139. }
  140. //---[ CStateMachineBase::fValidateStateTable ]---------------------
  141. //
  142. //
  143. // Description:
  144. // loops through all transitions and checks that
  145. // a) all possible states are start states
  146. // b) for every state, every possible action yields another state
  147. // Parameters:
  148. // -
  149. // Returns:
  150. // - true/false if state table is valid/invalid
  151. // History:
  152. // 6/5/2000 - t-toddc Created
  153. //
  154. //------------------------------------------------------------------
  155. BOOL CStateMachineBase::fValidateStateTable()
  156. {
  157. TraceFunctEnter("CStateMachineBase::fValidateStateTable");
  158. DWORD i, j, k; // iterators
  159. DWORD dwEndState;
  160. DWORD dwAction;
  161. DWORD dwCurrentState;
  162. BOOL fFoundEndStateAsStartState = false;
  163. BOOL fActionSupportedByEveryState = false;
  164. const STATE_TRANSITION* pTransitionTable;
  165. DWORD dwNumTransitions;
  166. BOOL fRetVal = false;
  167. // obtain the transition table
  168. getTransitionTable(&pTransitionTable, &dwNumTransitions);
  169. for(i = 0; i < dwNumTransitions; i++)
  170. {
  171. // initialize booleans within loop
  172. fFoundEndStateAsStartState = false;
  173. // grab the current action
  174. dwAction = pTransitionTable[i].dwAction;
  175. // grab the current end state
  176. dwEndState = pTransitionTable[i].dwNextState;
  177. // loop over all transitions
  178. for (j = 0; j < dwNumTransitions; j++)
  179. {
  180. // check that the current end state is a start state
  181. if (pTransitionTable[j].dwCurrentState == dwEndState)
  182. {
  183. fFoundEndStateAsStartState = true;
  184. }
  185. // check that every action is supported by every state
  186. fActionSupportedByEveryState = false;
  187. dwCurrentState = pTransitionTable[j].dwCurrentState;
  188. // the current action might not be in this particular transition,
  189. // but it must be in a transition with this dwCurrentState as the start state
  190. if (pTransitionTable[j].dwAction != dwAction)
  191. {
  192. // loop over all transitions again to guarantee the above.
  193. for(k = 0; k < dwNumTransitions; k++)
  194. {
  195. // there must exist a state transition with the current state
  196. // from above and the given action
  197. if (pTransitionTable[k].dwAction == dwAction &&
  198. pTransitionTable[k].dwCurrentState == dwCurrentState)
  199. {
  200. fActionSupportedByEveryState = true;
  201. break;
  202. }
  203. }
  204. }
  205. else
  206. {
  207. fActionSupportedByEveryState = true;
  208. }
  209. // bail on false if the current action is not supported by every state
  210. ASSERT(fActionSupportedByEveryState &&
  211. "Invalid state table: action not supported by every state");
  212. if (!fActionSupportedByEveryState)
  213. {
  214. fRetVal = false;
  215. DebugTrace((LPARAM) this,
  216. "Invalid state table: action not supported by every state");
  217. goto Cleanup;
  218. }
  219. // break out of inner loop if the current end state has been found
  220. // as a start state
  221. if (fFoundEndStateAsStartState)
  222. break;
  223. }
  224. // bail on false if an end state is not also a start state
  225. ASSERT(fFoundEndStateAsStartState &&
  226. "Invalid state table: an end state is not also a start state");
  227. if (!fFoundEndStateAsStartState)
  228. {
  229. fRetVal = false;
  230. DebugTrace((LPARAM) this,
  231. "Invalid state table: an end state is not also a start state");
  232. goto Cleanup;
  233. }
  234. }
  235. // if it makes it this far, it is undoubtedly valid.
  236. fRetVal = true;
  237. Cleanup:
  238. TraceFunctLeave();
  239. return fRetVal;
  240. }