123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- #include "stdafx.h"
- #include "SpFSM.h"
- #include "SpEntity.h"
- #include "SpMisc.h"
- #include "threadpool.h"
- #include "ListEntry.h"
- #include "dbgutil.h"
- #include "sp_def.h"
- #include "sp_svc.h"
- #include "sp_tmr.h"
- #ifdef _WIN32
- #include "sp_checkEntity.h"
- #endif //_WIN32
- struct FSMTimer
- {
- LIST_ENTRY entry;
- int iTimerId;
- sp_tmr_t *timer; // internal timer
- FSMBase *owner;
- FSMTimer(FSMBase *o) : timer(NULL), owner(o) { ListEntry_InitNode(&entry); }
- };
- static void __fsm_cb(threadpool_t *threadpool, void *arg, param_size_t param1, param_size_t param2)
- {
- FSMEvent *e = static_cast<FSMEvent*>(arg);
- FSMBase *pFSM = (FSMBase*)param1;
- try
- {
- pFSM->__ProcessEvent(e);
- e->DecRef(); // @
- }
- catch (...)
- {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
- //std::terminate();
- }
-
- }
- static void __tmr_cb(sp_tmr_t *timer, int err, void *user_data)
- {
- FSMTimer *pTimer = static_cast<FSMTimer*>(user_data);
- #ifdef _WIN32
- SetThreadGroupByResource(GetCurrentProcessId(), timer);
- #endif //_WIN32
- try
- {
- if (!err) {
- if (pTimer->entry.Flink) {
- ListEntry_DeleteNode(&pTimer->entry);
- FSMEvent *e = new FSMEvent(EVT_TIMER);
- e->param1 = (int)pTimer->iTimerId;
- pTimer->owner->__ProcessEvent(e);
- e->DecRef();
- }
- }
- sp_tmr_destroy(timer);
- }
- catch (...)
- {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
- //std::terminate();
- }
-
- }
- static void __tmr_destroy(sp_tmr_t *timer, void *user_data)
- {
- FSMTimer *pTimer = static_cast<FSMTimer*>(user_data);
- delete pTimer;
- }
- FSMBase::FSMBase() : m_iHookerCnt(0), m_strand(NULL), m_pEntity(NULL), m_lInTrans(0)
- {
- m_iState = FSM_STATE_INIT;
- ListEntry_InitHead(&m_timerlist);
- ListEntry_InitHead(&m_eventlist);
- }
- FSMBase::~FSMBase()
- {
- //TOOLKIT_ASSERT(m_iState == FSM_STATE_EXIT);
- while (!ListEntry_IsEmpty(&m_timerlist)) {
- FSMTimer *timer = CONTAINING_RECORD(m_timerlist.Flink, FSMTimer, entry);
- CancelTimer(timer->iTimerId);
- }
- while (!ListEntry_IsEmpty(&m_eventlist)) {
- FSMEvent *event = CONTAINING_RECORD(m_eventlist.Flink, FSMEvent, m_entry);
- ListEntry_DeleteNode(&event->m_entry);
- event->DecRef();
- }
- if (m_strand)
- strand_destroy((strand_t*)m_strand);
- }
- ErrorCodeEnum FSMBase::Init(CEntityBase *pEntity)
- {
- LOG_ASSERT(pEntity);
- LOG_ASSERT(m_iState == FSM_STATE_INIT || m_iState == FSM_STATE_EXIT);
- m_pEntity = pEntity;
- if (m_strand) {
- strand_destroy((strand_t*)m_strand);
- m_strand = NULL;
- }
- m_strand = NULL;
- m_iState = FSM_STATE_INIT;
- ErrorCodeEnum Error = OnInit();
- if (Error == Error_Succeed) {
- Trans(GetInitState());
- }
- else {
- //m_iState = FSM_STATE_ERROR;
- }
- return Error;
- }
- ErrorCodeEnum FSMBase::PostExitEvent()
- {
- Trans(FSM_STATE_EXIT);
- return Error_Succeed;
- }
- void FSMBase::PostEventLIFO(FSMEvent *e)
- {
- //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("post event last in first out: %d", e->iEvt);
- try
- {
- SpEntity *pEntity = dynamic_cast<SpEntity*>(m_pEntity->m_pEntityFunction);
- 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);
- }
- catch (...)
- {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
- }
- }
- void FSMBase::PostEventFIFO(FSMEvent *e)
- {
- //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("post event first in first out: %d", e->iEvt);
- try
- {
- SpEntity *pEntity = dynamic_cast<SpEntity*>(m_pEntity->m_pEntityFunction);
- threadpool_post_workitem_fifo2(sp_svc_get_threadpool(pEntity->get_svc()),
- (strand_t*)m_strand, &__fsm_cb, e, (param_size_t)(intptr_t)this, 0);
- }
- catch (...)
- {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
- //std::terminate();
- }
- }
- void FSMBase::Trans( int next )
- {
- try
- {
- if (next != m_iState) {
- FSMEvent *e = new FSMEvent(EVT_INTERNAL); // @
- e->param1 = (int)next;
- PostEventFIFO(e);
- m_lInTrans++;
- }
- }
- catch (...)
- {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
- //std::terminate();
- }
- }
- void FSMBase::__ProcessEvent(FSMEvent *e)
- {
- if (e->iEvt == EVT_INTERNAL) {
- m_lInTrans--;
- int old_state = m_iState;
- int new_state = e->param1;
- if (old_state != new_state) {
- OnHook(old_state, new_state); // dont change state here
- TOOLKIT_ASSERT(m_iState == old_state);
- if (old_state != FSM_STATE_INIT && old_state != FSM_STATE_ERROR) {
- OnStateExit(old_state);
- }
- m_iState = new_state;
- if (new_state != FSM_STATE_EXIT) {
- OnStateEntry(new_state);
- } else {
- OnExit();
- }
- }
- while (!m_lInTrans && !ListEntry_IsEmpty(&m_eventlist)) {
- FSMEvent *event = CONTAINING_RECORD(ListEntry_RemoveListHead(&m_eventlist), FSMEvent, m_entry);
- unsigned int rc;
- rc = OnStateEvent(event);
- if (!event->IsHandled()) {
- if (FindStateEvent(event->iEvt)) {
- event->SetHandled();
- }
- }
- if (event->IsHandled()) {
- int dst_state = MatchRule(m_iState, event->iEvt, rc);
- if (dst_state != m_iState) {
- Trans(dst_state);
- }
- } else {
- event->OnUnhandled();
- }
- event->SetHandled(FALSE);
- event->DecRef();
- }
- } else {
- if (m_lInTrans) {
- e->IncRef();
- ListEntry_AddTail(&m_eventlist, &e->m_entry);
- } else if(!InNotInitState()){
- unsigned int rc = OnStateEvent(e);
- if (!e->IsHandled()) {
- if (FindStateEvent(e->iEvt)) {
- e->SetHandled();
- }
- }
- if (e->IsHandled()) {
- int dst_state = MatchRule(m_iState, e->iEvt, rc);
- if (dst_state != m_iState) {
- Trans(dst_state);
- }
- } else {
- e->OnUnhandled();
- }
- e->SetHandled(FALSE);
- }
- else {
- DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("Ignore the FSMEvent id: %d", e->iEvt);
- if (e->IsHandled()) {
- /** [Gifur@2025429]*/
- }
- else {
- e->OnUnhandled();
- }
- e->SetHandled(FALSE);
- }
- }
- }
- void FSMBase::AddStateHooker( IFSMStateHooker *pHooker )
- {
- LOG_ASSERT(pHooker);
- LOG_ASSERT(m_iHookerCnt < MAX_HOOKER);
- m_arrHookers[m_iHookerCnt++] = pHooker;
- }
- void FSMBase::RemoveStateHooker( IFSMStateHooker *pHooker )
- {
- LOG_ASSERT(pHooker);
- for (int i = 0; i < m_iHookerCnt; ++i) {
- if (m_arrHookers[i] == pHooker) {
- if (i != m_iHookerCnt-1) {
- m_arrHookers[i] = m_arrHookers[m_iHookerCnt-1];
- }
- m_iHookerCnt--;
- break;
- }
- }
- }
- void FSMBase::OnHook( int iSrcState, int iDstState )
- {
- for (int i = 0; i < m_iHookerCnt; ++i) {
- IFSMStateHooker *pHooker = m_arrHookers[i];
- pHooker->OnStateTrans(iSrcState, iDstState);
- }
- }
- ErrorCodeEnum FSMBase::ScheduleTimer(int iTimerId, unsigned int timeout)
- {
- FSMTimer *pos;
- ListEntry_ForEach(pos, &m_timerlist, FSMTimer, entry) {
- if (pos->iTimerId == iTimerId) {
- return Error_Duplication;
- }
- }
- try
- {
- SpEntity *pEntity = dynamic_cast<SpEntity*>(m_pEntity->m_pEntityFunction);
- FSMTimer *pTimer = new FSMTimer(this);
- pTimer->iTimerId = iTimerId;
- sp_tmr_callback cb;
- int rc;
- cb.user_data = pTimer;
- cb.on_destroy = &__tmr_destroy;
- cb.on_timer = &__tmr_cb;
- rc = sp_tmr_create(sp_svc_get_tmr_mgr(pEntity->get_svc()), (strand_t*)m_strand, &cb, &pTimer->timer);
- if (rc != 0) {
- delete pTimer;
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("ScheduleTimer create tmr error");
- return SpTranslateError(rc);
- }
- ListEntry_AddTail(&m_timerlist, &pTimer->entry);
- rc = sp_tmr_schedule(pTimer->timer, timeout);
- if (rc != 0) {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("Schedule Timer error: %d", rc);
- sp_tmr_destroy(pTimer->timer);
- pTimer->timer = NULL;
- ListEntry_DeleteNode(&pTimer->entry);
- delete pTimer;
- return SpTranslateError(rc);
- }
- return Error_Succeed;
- }
- catch (...)
- {
- DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("Exception occurs at <%s>[%d]{%s}", __FUNCTION__, __LINE__, _GetFileName(__FILE__));
- //std::terminate();
- return Error_Exception;
- }
-
- }
- ErrorCodeEnum FSMBase::CancelTimer(int iTimerId)
- {
- FSMTimer *pos;
- ListEntry_ForEach(pos, &m_timerlist, FSMTimer, entry) {
- if (pos->iTimerId == iTimerId) {
- ListEntry_DeleteNode(&pos->entry);
- sp_tmr_cancel(pos->timer);
- return Error_Succeed;
- }
- }
- return Error_NotExist;
- }
|