SpFSM.cpp 6.7 KB

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