SpFSM.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "stdafx.h"
  2. #include "SpFSM.h"
  3. #include "SpEntity.h"
  4. #include "SpMisc.h"
  5. #include "threadpool.h"
  6. #include "ListEntry.h"
  7. #include "dbgutil.h"
  8. #include "sp_def.h"
  9. #include "sp_svc.h"
  10. #include "sp_tmr.h"
  11. #ifdef _WIN32
  12. #include "sp_checkEntity.h"
  13. #endif //_WIN32
  14. struct FSMTimer
  15. {
  16. LIST_ENTRY entry;
  17. int iTimerId;
  18. sp_tmr_t *timer; // internal timer
  19. FSMBase *owner;
  20. FSMTimer(FSMBase *o) : timer(NULL), owner(o) { ListEntry_InitNode(&entry); }
  21. };
  22. static void __fsm_cb(threadpool_t *threadpool, void *arg, param_size_t param1, param_size_t param2)
  23. {
  24. FSMEvent *e = static_cast<FSMEvent*>(arg);
  25. FSMBase *pFSM = (FSMBase*)param1;
  26. try
  27. {
  28. pFSM->__ProcessEvent(e);
  29. e->DecRef(); // @
  30. }
  31. catch (...)
  32. {
  33. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
  34. //std::terminate();
  35. }
  36. }
  37. static void __tmr_cb(sp_tmr_t *timer, int err, void *user_data)
  38. {
  39. FSMTimer *pTimer = static_cast<FSMTimer*>(user_data);
  40. #ifdef _WIN32
  41. SetThreadGroupByResource(GetCurrentProcessId(), timer);
  42. #endif //_WIN32
  43. try
  44. {
  45. if (!err) {
  46. if (pTimer->entry.Flink) {
  47. ListEntry_DeleteNode(&pTimer->entry);
  48. FSMEvent *e = new FSMEvent(EVT_TIMER);
  49. e->param1 = (int)pTimer->iTimerId;
  50. pTimer->owner->__ProcessEvent(e);
  51. e->DecRef();
  52. }
  53. }
  54. sp_tmr_destroy(timer);
  55. }
  56. catch (...)
  57. {
  58. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
  59. //std::terminate();
  60. }
  61. }
  62. static void __tmr_destroy(sp_tmr_t *timer, void *user_data)
  63. {
  64. FSMTimer *pTimer = static_cast<FSMTimer*>(user_data);
  65. delete pTimer;
  66. }
  67. FSMBase::FSMBase() : m_iHookerCnt(0), m_strand(NULL), m_pEntity(NULL), m_lInTrans(0)
  68. {
  69. m_iState = FSM_STATE_INIT;
  70. ListEntry_InitHead(&m_timerlist);
  71. ListEntry_InitHead(&m_eventlist);
  72. }
  73. FSMBase::~FSMBase()
  74. {
  75. //TOOLKIT_ASSERT(m_iState == FSM_STATE_EXIT);
  76. while (!ListEntry_IsEmpty(&m_timerlist)) {
  77. FSMTimer *timer = CONTAINING_RECORD(m_timerlist.Flink, FSMTimer, entry);
  78. CancelTimer(timer->iTimerId);
  79. }
  80. while (!ListEntry_IsEmpty(&m_eventlist)) {
  81. FSMEvent *event = CONTAINING_RECORD(m_eventlist.Flink, FSMEvent, m_entry);
  82. ListEntry_DeleteNode(&event->m_entry);
  83. event->DecRef();
  84. }
  85. if (m_strand)
  86. strand_destroy((strand_t*)m_strand);
  87. }
  88. ErrorCodeEnum FSMBase::Init(CEntityBase *pEntity)
  89. {
  90. LOG_ASSERT(pEntity);
  91. LOG_ASSERT(m_iState == FSM_STATE_INIT || m_iState == FSM_STATE_EXIT);
  92. m_pEntity = pEntity;
  93. if (m_strand) {
  94. strand_destroy((strand_t*)m_strand);
  95. m_strand = NULL;
  96. }
  97. m_strand = NULL;
  98. m_iState = FSM_STATE_INIT;
  99. ErrorCodeEnum Error = OnInit();
  100. if (Error == Error_Succeed) {
  101. Trans(GetInitState());
  102. }
  103. else {
  104. //m_iState = FSM_STATE_ERROR;
  105. }
  106. return Error;
  107. }
  108. ErrorCodeEnum FSMBase::PostExitEvent()
  109. {
  110. Trans(FSM_STATE_EXIT);
  111. return Error_Succeed;
  112. }
  113. void FSMBase::PostEventLIFO(FSMEvent *e)
  114. {
  115. //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("post event last in first out: %d", e->iEvt);
  116. try
  117. {
  118. SpEntity *pEntity = dynamic_cast<SpEntity*>(m_pEntity->m_pEntityFunction);
  119. threadpool_post_workitem_lifo2(sp_svc_get_threadpool(pEntity->get_svc()), (strand_t*)m_strand, &__fsm_cb, e, (param_size_t)(intptr_t)this, 0);
  120. }
  121. catch (...)
  122. {
  123. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
  124. }
  125. }
  126. void FSMBase::PostEventFIFO(FSMEvent *e)
  127. {
  128. //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("post event first in first out: %d", e->iEvt);
  129. try
  130. {
  131. SpEntity *pEntity = dynamic_cast<SpEntity*>(m_pEntity->m_pEntityFunction);
  132. threadpool_post_workitem_fifo2(sp_svc_get_threadpool(pEntity->get_svc()),
  133. (strand_t*)m_strand, &__fsm_cb, e, (param_size_t)(intptr_t)this, 0);
  134. }
  135. catch (...)
  136. {
  137. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
  138. //std::terminate();
  139. }
  140. }
  141. void FSMBase::Trans( int next )
  142. {
  143. try
  144. {
  145. if (next != m_iState) {
  146. FSMEvent *e = new FSMEvent(EVT_INTERNAL); // @
  147. e->param1 = (int)next;
  148. PostEventFIFO(e);
  149. m_lInTrans++;
  150. }
  151. }
  152. catch (...)
  153. {
  154. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
  155. //std::terminate();
  156. }
  157. }
  158. void FSMBase::__ProcessEvent(FSMEvent *e)
  159. {
  160. if (e->iEvt == EVT_INTERNAL) {
  161. m_lInTrans--;
  162. int old_state = m_iState;
  163. int new_state = e->param1;
  164. if (old_state != new_state) {
  165. OnHook(old_state, new_state); // dont change state here
  166. TOOLKIT_ASSERT(m_iState == old_state);
  167. if (old_state != FSM_STATE_INIT && old_state != FSM_STATE_ERROR) {
  168. OnStateExit(old_state);
  169. }
  170. m_iState = new_state;
  171. if (new_state != FSM_STATE_EXIT) {
  172. OnStateEntry(new_state);
  173. } else {
  174. OnExit();
  175. }
  176. }
  177. while (!m_lInTrans && !ListEntry_IsEmpty(&m_eventlist)) {
  178. FSMEvent *event = CONTAINING_RECORD(ListEntry_RemoveListHead(&m_eventlist), FSMEvent, m_entry);
  179. unsigned int rc;
  180. rc = OnStateEvent(event);
  181. if (!event->IsHandled()) {
  182. if (FindStateEvent(event->iEvt)) {
  183. event->SetHandled();
  184. }
  185. }
  186. if (event->IsHandled()) {
  187. int dst_state = MatchRule(m_iState, event->iEvt, rc);
  188. if (dst_state != m_iState) {
  189. Trans(dst_state);
  190. }
  191. } else {
  192. event->OnUnhandled();
  193. }
  194. event->SetHandled(FALSE);
  195. event->DecRef();
  196. }
  197. } else {
  198. if (m_lInTrans) {
  199. e->IncRef();
  200. ListEntry_AddTail(&m_eventlist, &e->m_entry);
  201. } else if(!InNotInitState()){
  202. unsigned int rc = OnStateEvent(e);
  203. if (!e->IsHandled()) {
  204. if (FindStateEvent(e->iEvt)) {
  205. e->SetHandled();
  206. }
  207. }
  208. if (e->IsHandled()) {
  209. int dst_state = MatchRule(m_iState, e->iEvt, rc);
  210. if (dst_state != m_iState) {
  211. Trans(dst_state);
  212. }
  213. } else {
  214. e->OnUnhandled();
  215. }
  216. e->SetHandled(FALSE);
  217. }
  218. else {
  219. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("Ignore the FSMEvent id: %d", e->iEvt);
  220. if (e->IsHandled()) {
  221. /** [Gifur@2025429]*/
  222. }
  223. else {
  224. e->OnUnhandled();
  225. }
  226. e->SetHandled(FALSE);
  227. }
  228. }
  229. }
  230. void FSMBase::AddStateHooker( IFSMStateHooker *pHooker )
  231. {
  232. LOG_ASSERT(pHooker);
  233. LOG_ASSERT(m_iHookerCnt < MAX_HOOKER);
  234. m_arrHookers[m_iHookerCnt++] = pHooker;
  235. }
  236. void FSMBase::RemoveStateHooker( IFSMStateHooker *pHooker )
  237. {
  238. LOG_ASSERT(pHooker);
  239. for (int i = 0; i < m_iHookerCnt; ++i) {
  240. if (m_arrHookers[i] == pHooker) {
  241. if (i != m_iHookerCnt-1) {
  242. m_arrHookers[i] = m_arrHookers[m_iHookerCnt-1];
  243. }
  244. m_iHookerCnt--;
  245. break;
  246. }
  247. }
  248. }
  249. void FSMBase::OnHook( int iSrcState, int iDstState )
  250. {
  251. for (int i = 0; i < m_iHookerCnt; ++i) {
  252. IFSMStateHooker *pHooker = m_arrHookers[i];
  253. pHooker->OnStateTrans(iSrcState, iDstState);
  254. }
  255. }
  256. ErrorCodeEnum FSMBase::ScheduleTimer(int iTimerId, unsigned int timeout)
  257. {
  258. FSMTimer *pos;
  259. ListEntry_ForEach(pos, &m_timerlist, FSMTimer, entry) {
  260. if (pos->iTimerId == iTimerId) {
  261. return Error_Duplication;
  262. }
  263. }
  264. try
  265. {
  266. SpEntity *pEntity = dynamic_cast<SpEntity*>(m_pEntity->m_pEntityFunction);
  267. FSMTimer *pTimer = new FSMTimer(this);
  268. pTimer->iTimerId = iTimerId;
  269. sp_tmr_callback cb;
  270. int rc;
  271. cb.user_data = pTimer;
  272. cb.on_destroy = &__tmr_destroy;
  273. cb.on_timer = &__tmr_cb;
  274. rc = sp_tmr_create(sp_svc_get_tmr_mgr(pEntity->get_svc()), (strand_t*)m_strand, &cb, &pTimer->timer);
  275. if (rc != 0) {
  276. delete pTimer;
  277. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("ScheduleTimer create tmr error");
  278. return SpTranslateError(rc);
  279. }
  280. ListEntry_AddTail(&m_timerlist, &pTimer->entry);
  281. rc = sp_tmr_schedule(pTimer->timer, timeout);
  282. if (rc != 0) {
  283. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("Schedule Timer error: %d", rc);
  284. sp_tmr_destroy(pTimer->timer);
  285. pTimer->timer = NULL;
  286. ListEntry_DeleteNode(&pTimer->entry);
  287. delete pTimer;
  288. return SpTranslateError(rc);
  289. }
  290. return Error_Succeed;
  291. }
  292. catch (...)
  293. {
  294. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
  295. //std::terminate();
  296. return Error_Exception;
  297. }
  298. }
  299. ErrorCodeEnum FSMBase::CancelTimer(int iTimerId)
  300. {
  301. FSMTimer *pos;
  302. ListEntry_ForEach(pos, &m_timerlist, FSMTimer, entry) {
  303. if (pos->iTimerId == iTimerId) {
  304. ListEntry_DeleteNode(&pos->entry);
  305. sp_tmr_cancel(pos->timer);
  306. return Error_Succeed;
  307. }
  308. }
  309. return Error_NotExist;
  310. }