#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(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(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(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(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(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(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; }