123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- // shmthread.h :
- //
- #if !defined(AGD_SHMTHREAD_H__C09C5E02_A3A0_4171_BA2E_045C3FE0C05C__INCLUDED_)
- #define AGD_SHMTHREAD_H__C09C5E02_A3A0_4171_BA2E_045C3FE0C05C__INCLUDED_
- #include <time.h>
- #include <pthread.h>
- #include <gfa/gfaipc.h>
- #include <QDebug>
- #include "shmvar.h"
- #define _SHM_SNEAK_PEEK 1
- #define _TRACK_TIME 0
- #define _TRACK_UPDATES 0
- #define _SHM_SCAN_INTERVAL_MS 100
- /////////////////////////////////////////////////////////////////////////////
- #define _INVALID_THREAD_ID 0
- /////////////////////////////////////////////////////////////////////////////
- // shmthread.h - Declarations:
- template<typename T, typename S>
- class CShmWatcher
- {
- public:
- CShmWatcher(HSHM hShm, T &rT, const void *pShm);
- virtual ~CShmWatcher(void);
- bool StartWatch(unsigned long nMsInterval = _SHM_SCAN_INTERVAL_MS);
- void StopWatch(void);
- static void* ShmWatchWorker(void *pParam);
- void Lock(void){
- ::GfaIpcLockSHM(m_hShm);}
- void Unlock(void){
- ::GfaIpcUnlockSHM(m_hShm);}
- #if _SHM_SNEAK_PEEK
- inline bool ShmPeek(void){
- Lock();
- bool bRet = !!memcmp(m_pCache, m_pShm, sizeof(S));
- Unlock();
- return bRet;}
- inline void UpdateCache(void){
- Lock();
- memcpy(m_pCache, m_pShm, sizeof(S));
- Unlock();}
- #endif // _SHM_SNEAK_PEEK
- private:
- struct timespec m_tsInterval;
- pthread_t m_threadID;
- HSHM m_hShm;
- T &m_rT;
- S *m_pCache;
- const void *m_pShm;
- };
- /////////////////////////////////////////////////////////////////////////////
- template<typename T, typename S>
- CShmWatcher<T, S>::CShmWatcher(HSHM hShm, T &rT, const void *pShm) : m_threadID(_INVALID_THREAD_ID),
- m_hShm(hShm),
- m_rT(rT),
- m_pCache(NULL),
- m_pShm(pShm)
- {
- #if _SHM_SNEAK_PEEK
- if(m_pShm)
- {
- m_pCache = new S;
- memcpy(m_pCache, pShm, sizeof(S));
- }
- else
- {
- Q_ASSERT_X(false, "CShmWatcher::CShmWatcher", "Invalid SHM pointer!");
- }
- #endif // _SHM_SNEAK_PEEK
- }
- template<typename T, typename S>
- CShmWatcher<T, S>::~CShmWatcher(void)
- {
- StopWatch();
- #if _SHM_SNEAK_PEEK
- if(m_pCache)
- {
- delete m_pCache;
- m_pCache = NULL;
- }
- #endif // _SHM_SNEAK_PEEK
- }
- /////////////////////////////////////////////////////////////////////////////
- template<typename T, typename S>
- bool CShmWatcher<T, S>::StartWatch(unsigned long nMsInterval)
- {
- Lock();
- if(m_threadID != _INVALID_THREAD_ID)
- {
- Unlock();
- return true;
- }
- Unlock();
- m_tsInterval.tv_sec = nMsInterval / 1000;
- m_tsInterval.tv_nsec = (nMsInterval % 1000) * 1000000;
- bool bRet = !::pthread_create(&m_threadID, NULL, &CShmWatcher<T, S>::ShmWatchWorker, reinterpret_cast<void*>(this));
- if(!bRet)
- {
- m_threadID = _INVALID_THREAD_ID;
- qDebug() << "CShmWatcher::StartWatch failed!";
- }
- else
- {
- qDebug() << "CShmWatcher::StartWatch success!";
- }
- return bRet;
- }
- template<typename T, typename S>
- void CShmWatcher<T, S>::StopWatch(void)
- {
- pthread_t threadID;
- Lock();
- if((threadID = m_threadID) != _INVALID_THREAD_ID)
- m_threadID = _INVALID_THREAD_ID;
- Unlock();
- if(threadID != _INVALID_THREAD_ID)
- {
- ::pthread_cancel(threadID);
- ::pthread_join(threadID, NULL);
- qDebug() << "CShmWatcher::StopWatch: thread exit!";
- }
- }
- template<typename T, typename S>
- void* CShmWatcher<T, S>::ShmWatchWorker(void *pParam)
- {
- if(pParam)
- {
- #if _TRACK_UPDATES
- CHECK_UPDATE_SHM_RETVAL rv;
- #endif // _TRACK_UPDATES
- #if _TRACK_TIME
- struct timespec tsStart, tsEnd;
- #endif // _TRACK_TIME
- #if _SHM_SNEAK_PEEK
- bool bUpdt;
- #endif // _SHM_SNEAK_PEEK
- CShmWatcher<T, S>* pSelf = reinterpret_cast<CShmWatcher<T, S>*>(pParam);
- do
- {
- #if _TRACK_TIME
- unsigned long long nStart, nEnd;
- double fTime;
- ::clock_gettime(CLOCK_MONOTONIC, &tsStart);
- #endif // _TRACK_TIME
- #if _SHM_SNEAK_PEEK
- bUpdt = pSelf->ShmPeek();
- if(bUpdt)
- {
- #endif // _SHM_SNEAK_PEEK
- #if _TRACK_UPDATES
- rv.nRetval = pSelf->m_rT.CheckUpdateShm();
- #else // _TRACK_UPDATES
- pSelf->m_rT.CheckUpdateShm();
- #endif // _TRACK_UPDATES
- #if _SHM_SNEAK_PEEK
- pSelf->UpdateCache();
- }
- #if _TRACK_UPDATES
- else
- {
- rv.nRetval = 0;
- }
- #endif // _TRACK_UPDATES
- #endif // _SHM_SNEAK_PEEK
- #if _TRACK_TIME
- ::clock_gettime(CLOCK_MONOTONIC, &tsEnd);
- nStart = tsStart.tv_sec * 1000000000 + tsStart.tv_nsec;
- nEnd = tsEnd.tv_sec * 1000000000 + tsEnd.tv_nsec;
- fTime = (double)(nEnd - nStart) / 1000000.0;
- qDebug() << "CShmWatcher::ShmWatchWorker: Scan / Update time: - " << fTime << "ms";
- #endif // _TRACK_TIME
- #if _TRACK_UPDATES
- qDebug() << "CShmWatcher::ShmWatchWorker: Variables scanned / updated: - " << rv.nChecked << "/" << rv.nUpdated;
- #endif // _TRACK_UPDATES
- ::nanosleep(&pSelf->m_tsInterval, NULL);
- }
- while(true);
- pSelf->Lock();
- pSelf->m_threadID = _INVALID_THREAD_ID;
- pSelf->Unlock();
- qDebug() << "CShmWatcher::ShmWatchWorker: thread ended gracefully!";
- }
- return NULL;
- }
- /////////////////////////////////////////////////////////////////////////////
- #endif // !defined(AGD_SHMTHREAD_H__C09C5E02_A3A0_4171_BA2E_045C3FE0C05C__INCLUDED_)
|