#include "stdafx.h" #include "SpBase.h" #include "SpEntity.h" #include "SpModule.h" #include "SpTimer.h" #include "SpMisc.h" #include "gettimeofday.h" #include "list.h" #include "spinlock.h" #include "memutil.h" #include "refcnt.h" //#include "hash.h" //#include "hashset.h" //#include "jhash.h" #include "sp_svc.h" #include "sp_dbg_export.h" #include "sp_tmr.h" #ifdef _WIN32 #include "sp_checkEntity.h" #endif //_WIN32 #include "dbgutil.h" struct SpTimer_key_t { DWORD dwTimerID; }; struct SpTimer { struct hlist_node hentry; DWORD dwInterval; SpTimer_key_t key; SpEntity *pEntity; volatile LONG lStop; IReleasable *pUserData; ITimerListener *pListener; struct timeval tmNext; sp_tmr_t *tmr; SpTimerList *pList; spinlock_t lock; DECLARE_REF_COUNT_MEMBER(iRefCount); }; struct SpTimerList { SpEntity *pEntity; spinlock_t lock; htable_t *ht_timer; }; static __inline unsigned int timer_key_hasher(const SpTimer_key_t *key) { return key->dwTimerID; } static __inline int timer_key_cmp(const SpTimer_key_t *key1, const SpTimer_key_t *key2) { return (int)key1->dwTimerID - (int)key2->dwTimerID; } IMPLEMENT_HTABLE_STATIC(timer, SpTimer_key_t, SpTimer, key, hentry, timer_key_hasher, timer_key_cmp) static void __SpTimerDestroy(SpTimer *pTimer) { sp_tmr_destroy(pTimer->tmr); if (pTimer->pUserData) { delete pTimer->pUserData; pTimer->pUserData = NULL; } pTimer->tmr = NULL; } IMPLEMENT_REF_COUNT_MT_STATIC(SpTimer, SpTimer, iRefCount, __SpTimerDestroy) static void tmr_callback(sp_tmr_t *timer, int err, void *user_data) { SpTimer *pTimer = (SpTimer *)user_data; if (!err && !pTimer->lStop) { #ifdef _WIN32 getEntityResource()->m_Entity = pTimer->pList->pEntity; #else GetSpModule()->SetThreadEntity(pTimer->pList->pEntity); #endif //_WIN32 pTimer->pListener->OnTimeout(pTimer->key.dwTimerID); // OnTimeout() spinlock_enter(&pTimer->lock, -1); if (!pTimer->lStop) { /* user may cancel in callback function */ unsigned int delay; struct timeval now; gettimeofday(&pTimer->tmNext, NULL); // 以当前时间重置定时器,防止修改系统时间造成死循环 timeval_add_msec(&pTimer->tmNext, pTimer->dwInterval); /*gettimeofday(&now, NULL); if (timeval_cmp(&now, &pTimer->tmNext) >= 0) { delay = 0; } else { delay = timeval_sub(&pTimer->tmNext, &now); }*/ delay = pTimer->dwInterval; SpTimer_inc_ref(pTimer); int rc = sp_tmr_schedule(timer, delay); if (rc != 0) { SpTimer_dec_ref(pTimer); DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("internal schedule timer failed!"); } } spinlock_leave(&pTimer->lock); } SpTimer_dec_ref(pTimer); } SpTimer *SpTimerCreate(SpTimerList *pList, DWORD dwTimerID, DWORD dwInterval, ITimerListener *pListener) { sp_svc_t *svc; SpTimer *pTimer = MALLOC_T(SpTimer); int rc; sp_tmr_callback cb; svc = (sp_svc_t*)pList->pEntity->get_svc(); INIT_HLIST_NODE(&pTimer->hentry); pTimer->pList = pList; pTimer->pEntity = pList->pEntity; pTimer->dwInterval = dwInterval; pTimer->key.dwTimerID = dwTimerID; pTimer->pListener = pListener; pTimer->pUserData = NULL; cb.user_data = pTimer; cb.on_timer = &tmr_callback; cb.on_destroy = NULL; rc = sp_tmr_create(sp_svc_get_tmr_mgr(svc), NULL, &cb, &pTimer->tmr); if (rc != 0) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("create internal tmr failed!"); free(pTimer); return NULL; } spinlock_init(&pTimer->lock); REF_COUNT_INIT(&pTimer->iRefCount); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("SpTimer created dwTimerId = %d, dwInterval=%d", dwTimerID, dwInterval); return pTimer; } void SpTimerDestroy(SpTimer *pTimer) { SpTimer_dec_ref(pTimer); } void SpTimerSetUserData(SpTimer *pTimer, IReleasable *pUserData) { pTimer->pUserData = pUserData; } void SpTimerGetUserData(SpTimer *pTimer, CSmartPointer &pUserData) { pUserData.Attach(pTimer->pUserData); pTimer->pUserData = NULL; } ErrorCodeEnum SpTimerStart(SpTimer *pTimer) { int rc; pTimer->lStop = 0; sp_svc_t* svc = static_cast(pTimer->pList->pEntity->get_svc()); gettimeofday(&pTimer->tmNext, NULL); timeval_add_msec(&pTimer->tmNext, pTimer->dwInterval); SpTimer_inc_ref(pTimer); #ifdef _WIN32 getEntityResource()->m_timer = pTimer; #endif //_WIN32 rc = sp_tmr_schedule(pTimer->tmr, pTimer->dwInterval); if (rc != 0) { SpTimer_dec_ref(pTimer); sp_tmr_destroy(pTimer->tmr); pTimer->tmr = NULL; return SpTranslateError(rc); } return Error_Succeed; } void SpTimerStop(SpTimer *pTimer) { if (pTimer->lStop) return; InterlockedExchange(&pTimer->lStop, 1); spinlock_enter(&pTimer->lock, -1); sp_tmr_cancel(pTimer->tmr); spinlock_leave(&pTimer->lock); } void SpTimerSetInterval(SpTimer *pTimer, DWORD dwInterval) { pTimer->dwInterval = dwInterval; } DWORD SpTimerGetInterval(SpTimer *pTimer) { return pTimer->dwInterval; } SpTimerList *SpTimerListCreate(SpEntity *pEntity) { SpTimerList *pList = MALLOC_T(SpTimerList); spinlock_init(&pList->lock); pList->ht_timer = htable_create(0); pList->pEntity = pEntity; return pList; } void SpTimerListDestroy(SpTimerList *pList) { TOOLKIT_ASSERT(pList); TOOLKIT_ASSERT(pList->ht_timer->count == 0); htable_destroy(pList->ht_timer); free(pList); } SpTimer *SpTimerListFind(SpTimerList *pList, DWORD dwTimerID) { TOOLKIT_ASSERT(pList); SpTimer_key_t key = {dwTimerID}; SpTimer* pTimer = timer_find(pList->ht_timer, &key); return pTimer; } void SpTimerListAdd(SpTimerList *pList, SpTimer *pTimer) { TOOLKIT_ASSERT(pTimer); timer_add(pList->ht_timer, pTimer); } void SpTimerListRemove(SpTimerList *pList, SpTimer *pTimer) { TOOLKIT_ASSERT(pTimer); timer_remove(pList->ht_timer, pTimer); } void SpTimerListLock(SpTimerList *pList) { TOOLKIT_ASSERT(pList); spinlock_enter(&pList->lock, -1); } void SpTimerListUnlock(SpTimerList *pList) { TOOLKIT_ASSERT(pList); spinlock_leave(&pList->lock); } void SpTimerListStopAll(SpTimerList *pList) { for (int i = 0; i < pList->ht_timer->size; ++i) { SpTimer *tpos; struct hlist_node *pos; hlist_for_each_entry(tpos, pos, &pList->ht_timer->buckets[i], SpTimer, hentry) { SpTimerStop(tpos); } } }