SpFSM.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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. virtual void __PostInit() { }
  120. protected:
  121. int m_iState;
  122. CEntityBase *m_pEntity;
  123. private:
  124. void OnHook(int iSrcState, int iDstState);
  125. enum {MAX_HOOKER = 32};
  126. IFSMStateHooker *m_arrHookers[MAX_HOOKER];
  127. int m_iHookerCnt;
  128. void *m_strand; // make sure FSM event execute at one thread!!!
  129. LIST_ENTRY m_timerlist;
  130. LIST_ENTRY m_eventlist;
  131. LONG m_lInTrans;
  132. };
  133. template<class T>
  134. class FSMImpl : public FSMBase
  135. {
  136. public:
  137. virtual void OnStateEntry(int state)
  138. {
  139. T *pT = static_cast<T*>(this);
  140. #ifdef _WIN32
  141. T::FSMStateEntry* entry = pT->GetState(state);
  142. #else
  143. auto entry = pT->GetState(state);
  144. #endif //_WIN32
  145. if (entry->pOnEntry) {
  146. (pT->*(entry->pOnEntry))();
  147. }
  148. }
  149. virtual void OnStateExit(int state)
  150. {
  151. T *pT = static_cast<T*>(this);
  152. #ifdef _WIN32
  153. T::FSMStateEntry* entry = pT->GetState(state);
  154. #else
  155. auto entry = pT->GetState(state);
  156. #endif //_WIN32
  157. if (entry->pOnExit) {
  158. (pT->*(entry->pOnExit))();
  159. }
  160. }
  161. virtual unsigned int OnStateEvent(FSMEvent *e)
  162. {
  163. T *pT = static_cast<T*>(this);
  164. #ifdef _WIN32
  165. T::FSMStateEntry* entry = pT->GetCurrState();
  166. #else
  167. auto entry = pT->GetCurrState();
  168. #endif //_WIN32
  169. return (pT->*(entry->pOnEvent))(e);
  170. }
  171. virtual int MatchRule(int state, int evt, unsigned int rc)
  172. {
  173. T *pT = static_cast<T*>(this);
  174. int n = pT->GetRuleCount();
  175. for (int i = 0; i < n; ++i) {
  176. FSMRuleEntry *entry = pT->GetRule(i);
  177. if (state == entry->src_state) {
  178. if (evt == entry->evt) {
  179. if (rc >= entry->result_start && rc <= entry->result_end)
  180. return entry->dst_state;
  181. }
  182. }
  183. }
  184. return state; // no match
  185. }
  186. virtual BOOL FindStateEvent(int evt)
  187. {
  188. T *pT = static_cast<T*>(this);
  189. int n = pT->GetRuleCount();
  190. for (int i = 0; i < n; ++i) {
  191. FSMRuleEntry *entry = pT->GetRule(i);
  192. if (entry->src_state == m_iState && entry->evt == evt)
  193. return TRUE;
  194. }
  195. return FALSE;
  196. }
  197. const char *GetStateName(int iState)
  198. {
  199. if (iState == FSM_STATE_INIT) {
  200. return "State_Start";
  201. } else if (iState == FSM_STATE_EXIT) {
  202. return "State_End";
  203. } else if (iState == FSM_STATE_ERROR) {
  204. return "State_Error";
  205. }
  206. else {
  207. T *pT = static_cast<T*>(this);
  208. #ifdef _WIN32
  209. T::FSMStateEntry* entry = pT->GetState(iState);
  210. #else
  211. auto entry = pT->GetState(iState);
  212. #endif //_WIN32
  213. return entry ? entry->pszName : NULL;
  214. }
  215. }
  216. const char *GetCurrStateName()
  217. {
  218. return GetStateName(m_iState);
  219. }
  220. };
  221. #define BEGIN_FSM_STATE(cls) \
  222. public: \
  223. typedef FSMStateEntryT<cls> FSMStateEntry; \
  224. typedef cls FSM; \
  225. private: \
  226. FSMStateEntry *__EntryTable(int *iNum) { \
  227. static FSMStateEntry tables[] = {
  228. #define FSM_STATE_ENTRY(id, name, onentry, onexit, onevent) \
  229. {id, name, NULL, &FSM::onentry, &FSM::onexit, &FSM::onevent},
  230. #define END_FSM_STATE() \
  231. }; \
  232. static int sorted = 0; \
  233. if (!sorted) { \
  234. int n = sizeof(tables)/sizeof(tables[0]); \
  235. for (int i = 0; i < n-1; ++i) { \
  236. FSMStateEntry *t = &tables[i]; \
  237. if (t->id != i) { \
  238. int j; \
  239. for (j = i+1; j < n; ++j) { \
  240. FSMStateEntry *tt = &tables[j]; \
  241. if (tt->id == i) \
  242. break; \
  243. } \
  244. assert(j < n); \
  245. FSMStateEntry tentry; \
  246. memcpy(&tentry, t, sizeof(FSMStateEntry)); \
  247. memcpy(t, &tables[j], sizeof(FSMStateEntry)); \
  248. memcpy(&tables[j], &tentry, sizeof(FSMStateEntry)); \
  249. } \
  250. } \
  251. sorted++; \
  252. } \
  253. if (iNum) \
  254. *iNum = sizeof(tables)/sizeof(tables[0]); \
  255. return &tables[0]; \
  256. } \
  257. public: \
  258. FSMStateEntry *GetCurrState() \
  259. { \
  260. return GetState(m_iState); \
  261. } \
  262. FSMStateEntry *GetState(int iState) \
  263. { \
  264. int num; \
  265. FSMStateEntry *t = __EntryTable(&num); \
  266. assert(iState < num); \
  267. return t + iState; \
  268. } \
  269. int GetStateCount() \
  270. { \
  271. int num; \
  272. __EntryTable(&num); \
  273. return num; \
  274. }
  275. #define BEGIN_FSM_RULE(cls, init_state_id) \
  276. public: \
  277. virtual int GetInitState() { return init_state_id; } \
  278. private: \
  279. FSMRuleEntry *__RuleTable(int *iNum) { \
  280. static struct FSMRuleEntry table[] = {
  281. #define FSM_RULE_ENTRY(src_state_id, dst_state_id, evt_id, action_result) \
  282. {src_state_id, dst_state_id, evt_id, action_result, action_result},
  283. #define FSM_RULE_ENTRY_RANGE(src_state_id, dst_state_id, evt_id, action_result_start, action_result_end) \
  284. {src_state_id, dst_state_id, evt_id, action_result_start, action_result_end},
  285. #define FSM_RULE_ENTRY_ANY(src_state_id, dst_state_id, evt_id) \
  286. {src_state_id, dst_state_id, evt_id, 0, (unsigned int)-1},
  287. #define END_FSM_RULE() \
  288. }; \
  289. if (iNum) \
  290. *iNum = sizeof(table)/sizeof(table[0]); \
  291. return &table[0]; \
  292. } \
  293. public: \
  294. FSMRuleEntry * GetRule(int iRule) \
  295. { \
  296. int num; \
  297. FSMRuleEntry *t = __RuleTable(&num); \
  298. assert(iRule < num); \
  299. return t + iRule; \
  300. } \
  301. int GetRuleCount() \
  302. { \
  303. int num; \
  304. __RuleTable(&num); \
  305. return num; \
  306. }
  307. #endif // __SPFSM_H