|
@@ -25,15 +25,16 @@
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
-const int CGfaTimer::m_nPulseFreq[] = {250, 500, 750, 1000, 1500, 2000, 5000, 10000};
|
|
|
|
|
|
+const int CGfaTimer::m_nPulseFreq[GTCP_Last] = {250, 500, 750, 1000, 1500, 2000, 5000, 10000};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
CGfaTimer::CGfaTimer(void) : m_pTimer(NULL), m_nTimerCount(0), m_nTimerIncrement(0), m_nClockCount(0), m_nClockPulse(0), m_threadID(_INVALID_THREAD_ID), m_bProcessTimers(false)
|
|
CGfaTimer::CGfaTimer(void) : m_pTimer(NULL), m_nTimerCount(0), m_nTimerIncrement(0), m_nClockCount(0), m_nClockPulse(0), m_threadID(_INVALID_THREAD_ID), m_bProcessTimers(false)
|
|
{
|
|
{
|
|
memset(&m_timInterval, 0, sizeof(m_timInterval));
|
|
memset(&m_timInterval, 0, sizeof(m_timInterval));
|
|
|
|
+ memset(m_ClkPulseCallbackTable, 0, sizeof(m_ClkPulseCallbackTable));
|
|
|
|
|
|
- if(!m_mutex.Create())
|
|
|
|
|
|
+ if(!m_mutex.Create(true))
|
|
{
|
|
{
|
|
TRACE("CGfaTimer::CGfaTimer: failed to create mutex!\n");
|
|
TRACE("CGfaTimer::CGfaTimer: failed to create mutex!\n");
|
|
throw -1;
|
|
throw -1;
|
|
@@ -110,22 +111,77 @@ void CGfaTimer::Release(void)
|
|
{
|
|
{
|
|
if(m_pTimer)
|
|
if(m_pTimer)
|
|
{
|
|
{
|
|
|
|
+ m_mutex.Lock();
|
|
if(m_threadID != _INVALID_THREAD_ID)
|
|
if(m_threadID != _INVALID_THREAD_ID)
|
|
{
|
|
{
|
|
m_bProcessTimers = false;
|
|
m_bProcessTimers = false;
|
|
|
|
+ m_mutex.Unlock();
|
|
::pthread_join(m_threadID, NULL);
|
|
::pthread_join(m_threadID, NULL);
|
|
|
|
+ m_mutex.Lock();
|
|
m_threadID = _INVALID_THREAD_ID;
|
|
m_threadID = _INVALID_THREAD_ID;
|
|
}
|
|
}
|
|
|
|
|
|
m_nTimerCount = m_nTimerIncrement = m_nClockCount = m_nClockPulse = 0;
|
|
m_nTimerCount = m_nTimerIncrement = m_nClockCount = m_nClockPulse = 0;
|
|
delete [] m_pTimer;
|
|
delete [] m_pTimer;
|
|
m_pTimer = NULL;
|
|
m_pTimer = NULL;
|
|
|
|
+ m_mutex.Unlock();
|
|
TRACE("CGfaTimer::Release: Timer released.\n");
|
|
TRACE("CGfaTimer::Release: Timer released.\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
+void CGfaTimer::RegisterTimerCallback(int tnum, pfnTIMERCALLBACK pfnCallback, void *pContext)
|
|
|
|
+{
|
|
|
|
+ _VALIDATE_TIMER_VOID(tnum);
|
|
|
|
+ if(pfnCallback)
|
|
|
|
+ {
|
|
|
|
+ m_mutex.Lock();
|
|
|
|
+ m_pTimer[tnum].pfnCallback = pfnCallback;
|
|
|
|
+ m_pTimer[tnum].pContext = pContext;
|
|
|
|
+ m_pTimer[tnum].bCallScheduled = false;
|
|
|
|
+ m_mutex.Unlock();
|
|
|
|
+ TRACE("CGfaTimer::RegisterTimerCallback: Timer %d - callback: %p, context: %p.\n", tnum, pfnCallback, pContext);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ m_mutex.Lock();
|
|
|
|
+ m_pTimer[tnum].pfnCallback = NULL;
|
|
|
|
+ m_pTimer[tnum].pContext = NULL;
|
|
|
|
+ m_pTimer[tnum].bCallScheduled = false;
|
|
|
|
+ m_mutex.Unlock();
|
|
|
|
+ TRACE("CGfaTimer::RegisterTimerCallback: Timer %d - Unregister callback.\n", tnum);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void CGfaTimer::RegisterClockPulseCallback(GfaTimerClockPulse cp, pfnPULSECALLBACK pfnCallback, void *pContext)
|
|
|
|
+{
|
|
|
|
+ if(cp <= GTCP_Invalid || cp >= GTCP_Last)
|
|
|
|
+ {
|
|
|
|
+ TRACE("CGfaTimer::RegisterClockPulseCallback: invalid clock pulse %d!\n", cp);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(pfnCallback)
|
|
|
|
+ {
|
|
|
|
+ m_mutex.Lock();
|
|
|
|
+ m_ClkPulseCallbackTable[cp].pfnCallback = pfnCallback;
|
|
|
|
+ m_ClkPulseCallbackTable[cp].pContext = pContext;
|
|
|
|
+ m_mutex.Unlock();
|
|
|
|
+ TRACE("CGfaTimer::RegisterClockPulseCallback: Clock pulse %dms: Register callback: %p, context: %p.\n", CGfaTimer::m_nPulseFreq[cp], pfnCallback, pContext);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ m_mutex.Lock();
|
|
|
|
+ m_ClkPulseCallbackTable[cp].pfnCallback = NULL;
|
|
|
|
+ m_ClkPulseCallbackTable[cp].pContext = NULL;
|
|
|
|
+ m_mutex.Unlock();
|
|
|
|
+ TRACE("CGfaTimer::RegisterClockPulseCallback: Clock pulse %dms: Unregister callback.\n", CGfaTimer::m_nPulseFreq[cp]);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
bool CGfaTimer::ValidateTimer(int tnum, const char *pszCaller)
|
|
bool CGfaTimer::ValidateTimer(int tnum, const char *pszCaller)
|
|
{
|
|
{
|
|
if(!m_pTimer)
|
|
if(!m_pTimer)
|
|
@@ -218,7 +274,7 @@ void CGfaTimer::tw_set(int tnum, unsigned long val)
|
|
|
|
|
|
int CGfaTimer::cp_test(GfaTimerClockPulse cp)
|
|
int CGfaTimer::cp_test(GfaTimerClockPulse cp)
|
|
{
|
|
{
|
|
- if(cp >= GTCP_250ms && cp <= GTCP_10000ms)
|
|
|
|
|
|
+ if(cp > GTCP_Invalid && cp < GTCP_Last)
|
|
{
|
|
{
|
|
return !!(m_nClockPulse & (0x00000001 << cp));
|
|
return !!(m_nClockPulse & (0x00000001 << cp));
|
|
}
|
|
}
|
|
@@ -248,8 +304,25 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
|
|
|
|
|
|
::clock_gettime(CLOCK_MONOTONIC, &tsDueTime);
|
|
::clock_gettime(CLOCK_MONOTONIC, &tsDueTime);
|
|
|
|
|
|
|
|
+ /////////////////////////////////////////////////////////////////////////
|
|
|
|
+ // enter loop
|
|
|
|
+
|
|
do
|
|
do
|
|
{
|
|
{
|
|
|
|
+ /////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
|
|
+ CGfaTimer::AddTimeSpecs(tsDueTime, pSelf->m_timInterval, tsDueTime);
|
|
|
|
+
|
|
|
|
+ if((nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL)))
|
|
|
|
+ {
|
|
|
|
+ while(nRet && (errno == EINTR))
|
|
|
|
+ {
|
|
|
|
+ errno = 0;
|
|
|
|
+ nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ /////////////////////////////////////////////////////////////////////
|
|
|
|
+
|
|
for(int i = 0; i < pSelf->m_nTimerCount; i++)
|
|
for(int i = 0; i < pSelf->m_nTimerCount; i++)
|
|
{
|
|
{
|
|
GFA_TIMER &rt = pSelf->m_pTimer[i];
|
|
GFA_TIMER &rt = pSelf->m_pTimer[i];
|
|
@@ -257,18 +330,29 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
|
|
pSelf->m_mutex.Lock();
|
|
pSelf->m_mutex.Lock();
|
|
if(rt.tf)
|
|
if(rt.tf)
|
|
{
|
|
{
|
|
- if(rt.tw >= pSelf->m_nTimerIncrement)
|
|
|
|
|
|
+ if(rt.tw > pSelf->m_nTimerIncrement)
|
|
rt.tw -= pSelf->m_nTimerIncrement;
|
|
rt.tw -= pSelf->m_nTimerIncrement;
|
|
else if(rt.tw)
|
|
else if(rt.tw)
|
|
|
|
+ {
|
|
rt.tw = 0;
|
|
rt.tw = 0;
|
|
|
|
+ if(rt.pfnCallback)
|
|
|
|
+ rt.bCallScheduled = true;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ else if(rt.tw)
|
|
{
|
|
{
|
|
rt.tw = 0;
|
|
rt.tw = 0;
|
|
}
|
|
}
|
|
pSelf->m_mutex.Unlock();
|
|
pSelf->m_mutex.Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /////////////////////////////////////////////////////////////////////
|
|
|
|
+ // process clock pulses
|
|
|
|
+
|
|
|
|
+ pSelf->m_mutex.Lock();
|
|
|
|
+ bool bDoCallbacks = false;
|
|
|
|
+ unsigned long nPrevClockPulse = pSelf->m_nClockPulse;
|
|
|
|
+ unsigned long nScheduled;
|
|
pSelf->m_nClockCount += pSelf->m_nTimerIncrement;
|
|
pSelf->m_nClockCount += pSelf->m_nTimerIncrement;
|
|
|
|
|
|
if(!(pSelf->m_nClockCount % CGfaTimer::m_nPulseFreq[0]))
|
|
if(!(pSelf->m_nClockCount % CGfaTimer::m_nPulseFreq[0]))
|
|
@@ -276,7 +360,7 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
|
|
unsigned long nPulseMask = 1;
|
|
unsigned long nPulseMask = 1;
|
|
pSelf->m_nClockPulse ^= nPulseMask;
|
|
pSelf->m_nClockPulse ^= nPulseMask;
|
|
|
|
|
|
- for(size_t i = 1; i < _COUNTOF(CGfaTimer::m_nPulseFreq); i++)
|
|
|
|
|
|
+ for(int i = 1; i < GTCP_Last; i++)
|
|
{
|
|
{
|
|
nPulseMask <<= 1;
|
|
nPulseMask <<= 1;
|
|
|
|
|
|
@@ -285,18 +369,50 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
|
|
pSelf->m_nClockPulse ^= nPulseMask;
|
|
pSelf->m_nClockPulse ^= nPulseMask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ bDoCallbacks = true;
|
|
|
|
+ nScheduled = pSelf->m_nClockPulse ^ nPrevClockPulse;
|
|
}
|
|
}
|
|
|
|
|
|
- CGfaTimer::AddTimeSpecs(tsDueTime, pSelf->m_timInterval, tsDueTime);
|
|
|
|
|
|
+ pSelf->m_mutex.Unlock();
|
|
|
|
|
|
- if((nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL)))
|
|
|
|
|
|
+ /////////////////////////////////////////////////////////////////////
|
|
|
|
+ // call clock pulse callbacks
|
|
|
|
+
|
|
|
|
+ if(bDoCallbacks)
|
|
{
|
|
{
|
|
- while(nRet && (errno == EINTR))
|
|
|
|
|
|
+ unsigned long nPulseMask = 1;
|
|
|
|
+
|
|
|
|
+ for(int i = GTCP_250ms; i < GTCP_Last; i++, nPulseMask <<= 1)
|
|
{
|
|
{
|
|
- errno = 0;
|
|
|
|
- nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL);
|
|
|
|
|
|
+ pSelf->m_mutex.Lock();
|
|
|
|
+ pfnPULSECALLBACK pfnCallback = pSelf->m_ClkPulseCallbackTable[i].pfnCallback;
|
|
|
|
+ void *pContext = pSelf->m_ClkPulseCallbackTable[i].pContext;
|
|
|
|
+ int nState = !!(pSelf->m_nClockPulse & nPulseMask);
|
|
|
|
+ pSelf->m_mutex.Unlock();
|
|
|
|
+
|
|
|
|
+ if(pfnCallback && (nScheduled & nPulseMask))
|
|
|
|
+ {
|
|
|
|
+ (*pfnCallback)((GfaTimerClockPulse)i, nState, pContext);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /////////////////////////////////////////////////////////////////////
|
|
|
|
+ // process timer callbacks
|
|
|
|
+
|
|
|
|
+ for(int i = 0; i < pSelf->m_nTimerCount; i++)
|
|
|
|
+ {
|
|
|
|
+ GFA_TIMER &rt = pSelf->m_pTimer[i];
|
|
|
|
+
|
|
|
|
+ pSelf->m_mutex.Lock();
|
|
|
|
+ if(rt.pfnCallback && rt.tf && rt.bCallScheduled && !rt.tw)
|
|
|
|
+ {
|
|
|
|
+ rt.bCallScheduled = false;
|
|
|
|
+ (*rt.pfnCallback)(i, rt.pContext);
|
|
|
|
+ }
|
|
|
|
+ pSelf->m_mutex.Unlock();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
while(pSelf->m_bProcessTimers);
|
|
while(pSelf->m_bProcessTimers);
|
|
|
|
|