SpFSM.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #ifndef __SPFSM_H
  2. #define __SPFSM_H
  3. #pragma once
  4. #include "SpBase.h"
  5. #include "ListEntry.h"
  6. #ifndef PARAM_SIZE_DEFINED
  7. #define PARAM_SIZE_DEFINED
  8. #ifdef _WIN32
  9. typedef int param_size_t;
  10. #else
  11. #if (defined(__x86_64__) || defined(__aarch64__))
  12. typedef intptr_t param_size_t;
  13. #elif defined(__i386__)
  14. typedef int param_size_t;
  15. #else
  16. typedef intptr_t param_size_t;
  17. #endif
  18. #endif //_WIN32
  19. #endif // !PARAM_SIZE_DEFINED
  20. /** finite state machine */
  21. enum FSMEventEnum
  22. {
  23. EVT_INTERNAL, // internal usage
  24. EVT_TIMER, // timer evt
  25. EVT_MAINPAGE_DISPLAY, //the business main page display
  26. EVT_USER, // use defin Event must from here
  27. };
  28. #define FSM_STATE_INIT -1 // the initial state of the FSM
  29. #define FSM_STATE_EXIT -2 // the exit state of the FSM
  30. #define FSM_STATE_ERROR -3 // the error state of the FSM
  31. struct FSMEvent
  32. {
  33. int iEvt;
  34. param_size_t param1;
  35. param_size_t param2;
  36. FSMEvent(int evt)
  37. : m_ref_cnt(1)
  38. , iEvt(evt)
  39. ,param1(-1) /** NOTICES!! maybe make some noise for real online FSM [5/26/2020 Gifur] */
  40. ,param2(-1) /** NOTICES!! maybe make some noise for real online FSM [5/26/2020 Gifur] */
  41. , m_bHandled(FALSE)
  42. {
  43. m_entry.Flink = m_entry.Blink = &m_entry;
  44. }
  45. virtual ~FSMEvent() {}
  46. void IncRef() { InterlockedIncrement(&m_ref_cnt); }
  47. void DecRef() { if (0 == InterlockedDecrement(&m_ref_cnt)) {delete this;} }
  48. void SetHandled(BOOL bHandled = TRUE) { m_bHandled = bHandled; }
  49. BOOL IsHandled() { return m_bHandled; }
  50. virtual void OnUnhandled() {}
  51. private:
  52. BOOL m_bHandled;
  53. LONG m_ref_cnt;
  54. LIST_ENTRY m_entry;
  55. friend class FSMBase;
  56. };
  57. template<class T>
  58. struct FSMStateEntryT
  59. {
  60. int id;
  61. const char *pszName;
  62. void *pUserData;
  63. void (T::*pOnEntry)();
  64. void (T::*pOnExit)();
  65. unsigned int (T::*pOnEvent)(FSMEvent *e);
  66. };
  67. struct FSMRuleEntry
  68. {
  69. int src_state;
  70. int dst_state;
  71. int evt;
  72. unsigned int result_start;
  73. unsigned int result_end;
  74. };
  75. struct IFSMStateHooker
  76. {
  77. virtual void OnStateTrans(int iSrcState, int iDstState)=0;
  78. };
  79. class SPBASE_API FSMBase
  80. {
  81. public:
  82. FSMBase();
  83. virtual ~FSMBase();
  84. ErrorCodeEnum Init(CEntityBase *pEntity); // try start the state machine
  85. ErrorCodeEnum PostExitEvent(); // active close FSM, force it into FSM_STATE_EXIT, so OnExit() could be called
  86. CEntityBase *GetEntityBase() { return m_pEntity; }
  87. void PostEventLIFO(FSMEvent *e);
  88. void PostEventFIFO(FSMEvent *e);
  89. ErrorCodeEnum ScheduleTimer(int iTimerId, unsigned int timeout); // iTimerId user define, one shot timer
  90. ErrorCodeEnum CancelTimer(int iTimerId);
  91. void AddStateHooker(IFSMStateHooker *pHooker);
  92. void RemoveStateHooker(IFSMStateHooker *pHooker);
  93. virtual int GetInitState() = 0;
  94. virtual ErrorCodeEnum OnInit() { return Error_Succeed; }
  95. virtual ErrorCodeEnum OnExit() { return Error_Succeed; }
  96. virtual void OnStateEntry(int state)=0;
  97. virtual void OnStateExit(int state)=0;
  98. virtual unsigned int OnStateEvent(FSMEvent *e)=0;
  99. virtual int MatchRule(int state, int evt, unsigned int rc)=0;
  100. virtual BOOL FindStateEvent(int evt)=0;
  101. protected:
  102. const bool InNotInitState() const
  103. {
  104. return (m_iState == FSM_STATE_INIT || m_iState == FSM_STATE_EXIT || m_iState == FSM_STATE_ERROR);
  105. }
  106. private:
  107. void Trans(int next);
  108. #ifdef _WIN32
  109. #if (!defined(SPABASE_LINKED_AS_STATIC_LIBRARY) && !defined(SPBASE_EXPORTS))
  110. private:
  111. #else
  112. public:
  113. #endif
  114. #else
  115. public:
  116. #endif //_WIN32
  117. void __ProcessEvent(FSMEvent *e);
  118. protected:
  119. int m_iState;
  120. CEntityBase *m_pEntity;
  121. private:
  122. void OnHook(int iSrcState, int iDstState);
  123. enum {MAX_HOOKER = 32};
  124. IFSMStateHooker *m_arrHookers[MAX_HOOKER];
  125. int m_iHookerCnt;
  126. void *m_strand; // make sure FSM event execute at one thread!!!
  127. LIST_ENTRY m_timerlist;
  128. LIST_ENTRY m_eventlist;
  129. LONG m_lInTrans;
  130. };
  131. template<class T>
  132. class FSMImpl : public FSMBase
  133. {
  134. public:
  135. virtual void OnStateEntry(int state)
  136. {
  137. T *pT = static_cast<T*>(this);
  138. #ifdef _WIN32
  139. T::FSMStateEntry* entry = pT->GetState(state);
  140. #else
  141. auto entry = pT->GetState(state);
  142. #endif //_WIN32
  143. if (entry->pOnEntry) {
  144. (pT->*(entry->pOnEntry))();
  145. }
  146. }
  147. virtual void OnStateExit(int state)
  148. {
  149. T *pT = static_cast<T*>(this);
  150. #ifdef _WIN32
  151. T::FSMStateEntry* entry = pT->GetState(state);
  152. #else
  153. auto entry = pT->GetState(state);
  154. #endif //_WIN32
  155. if (entry->pOnExit) {
  156. (pT->*(entry->pOnExit))();
  157. }
  158. }
  159. virtual unsigned int OnStateEvent(FSMEvent *e)
  160. {
  161. T *pT = static_cast<T*>(this);
  162. #ifdef _WIN32
  163. T::FSMStateEntry* entry = pT->GetCurrState();
  164. #else
  165. auto entry = pT->GetCurrState();
  166. #endif //_WIN32
  167. return (pT->*(entry->pOnEvent))(e);
  168. }
  169. virtual int MatchRule(int state, int evt, unsigned int rc)
  170. {
  171. T *pT = static_cast<T*>(this);
  172. int n = pT->GetRuleCount();
  173. for (int i = 0; i < n; ++i) {
  174. FSMRuleEntry *entry = pT->GetRule(i);
  175. if (state == entry->src_state) {
  176. if (evt == entry->evt) {
  177. if (rc >= entry->result_start && rc <= entry->result_end)
  178. return entry->dst_state;
  179. }
  180. }
  181. }
  182. return state; // no match
  183. }
  184. virtual BOOL FindStateEvent(int evt)
  185. {
  186. T *pT = static_cast<T*>(this);
  187. int n = pT->GetRuleCount();
  188. for (int i = 0; i < n; ++i) {
  189. FSMRuleEntry *entry = pT->GetRule(i);
  190. if (entry->src_state == m_iState && entry->evt == evt)
  191. return TRUE;
  192. }
  193. return FALSE;
  194. }
  195. const char *GetStateName(int iState)
  196. {
  197. if (iState == FSM_STATE_INIT) {
  198. return "State_Start";
  199. } else if (iState == FSM_STATE_EXIT) {
  200. return "State_End";
  201. } else if (iState == FSM_STATE_ERROR) {
  202. return "State_Error";
  203. }
  204. else {
  205. T *pT = static_cast<T*>(this);
  206. #ifdef _WIN32
  207. T::FSMStateEntry* entry = pT->GetState(iState);
  208. #else
  209. auto entry = pT->GetState(iState);
  210. #endif //_WIN32
  211. return entry ? entry->pszName : NULL;
  212. }
  213. }
  214. const char *GetCurrStateName()
  215. {
  216. return GetStateName(m_iState);
  217. }
  218. };
  219. #define BEGIN_FSM_STATE(cls) \
  220. public: \
  221. typedef FSMStateEntryT<cls> FSMStateEntry; \
  222. typedef cls FSM; \
  223. private: \
  224. FSMStateEntry *__EntryTable(int *iNum) { \
  225. static FSMStateEntry tables[] = {
  226. #define FSM_STATE_ENTRY(id, name, onentry, onexit, onevent) \
  227. {id, name, NULL, &FSM::onentry, &FSM::onexit, &FSM::onevent},
  228. #define END_FSM_STATE() \
  229. }; \
  230. static int sorted = 0; \
  231. if (!sorted) { \
  232. int n = sizeof(tables)/sizeof(tables[0]); \
  233. for (int i = 0; i < n-1; ++i) { \
  234. FSMStateEntry *t = &tables[i]; \
  235. if (t->id != i) { \
  236. int j; \
  237. for (j = i+1; j < n; ++j) { \
  238. FSMStateEntry *tt = &tables[j]; \
  239. if (tt->id == i) \
  240. break; \
  241. } \
  242. assert(j < n); \
  243. FSMStateEntry tentry; \
  244. memcpy(&tentry, t, sizeof(FSMStateEntry)); \
  245. memcpy(t, &tables[j], sizeof(FSMStateEntry)); \
  246. memcpy(&tables[j], &tentry, sizeof(FSMStateEntry)); \
  247. } \
  248. } \
  249. sorted++; \
  250. } \
  251. if (iNum) \
  252. *iNum = sizeof(tables)/sizeof(tables[0]); \
  253. return &tables[0]; \
  254. } \
  255. public: \
  256. FSMStateEntry *GetCurrState() \
  257. { \
  258. return GetState(m_iState); \
  259. } \
  260. FSMStateEntry *GetState(int iState) \
  261. { \
  262. int num; \
  263. FSMStateEntry *t = __EntryTable(&num); \
  264. assert(iState < num); \
  265. return t + iState; \
  266. } \
  267. int GetStateCount() \
  268. { \
  269. int num; \
  270. __EntryTable(&num); \
  271. return num; \
  272. }
  273. #define BEGIN_FSM_RULE(cls, init_state_id) \
  274. public: \
  275. virtual int GetInitState() { return init_state_id; } \
  276. private: \
  277. FSMRuleEntry *__RuleTable(int *iNum) { \
  278. static struct FSMRuleEntry table[] = {
  279. #define FSM_RULE_ENTRY(src_state_id, dst_state_id, evt_id, action_result) \
  280. {src_state_id, dst_state_id, evt_id, action_result, action_result},
  281. #define FSM_RULE_ENTRY_RANGE(src_state_id, dst_state_id, evt_id, action_result_start, action_result_end) \
  282. {src_state_id, dst_state_id, evt_id, action_result_start, action_result_end},
  283. #define FSM_RULE_ENTRY_ANY(src_state_id, dst_state_id, evt_id) \
  284. {src_state_id, dst_state_id, evt_id, 0, (unsigned int)-1},
  285. #define END_FSM_RULE() \
  286. }; \
  287. if (iNum) \
  288. *iNum = sizeof(table)/sizeof(table[0]); \
  289. return &table[0]; \
  290. } \
  291. public: \
  292. FSMRuleEntry * GetRule(int iRule) \
  293. { \
  294. int num; \
  295. FSMRuleEntry *t = __RuleTable(&num); \
  296. assert(iRule < num); \
  297. return t + iRule; \
  298. } \
  299. int GetRuleCount() \
  300. { \
  301. int num; \
  302. __RuleTable(&num); \
  303. return num; \
  304. }
  305. #endif // __SPFSM_H