shmthread.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // shmthread.h :
  2. //
  3. #if !defined(AGD_SHMTHREAD_H__C09C5E02_A3A0_4171_BA2E_045C3FE0C05C__INCLUDED_)
  4. #define AGD_SHMTHREAD_H__C09C5E02_A3A0_4171_BA2E_045C3FE0C05C__INCLUDED_
  5. #include <time.h>
  6. #include <pthread.h>
  7. #include <gfa/gfaipc.h>
  8. #include <QDebug>
  9. #ifndef _LIBBUILD
  10. #include <gfa/svc/shmqml/shmvar.h>
  11. #else // _LIBBUILD
  12. #include "shmvar.h"
  13. #endif // _LIBBUILD
  14. #define _SHM_SNEAK_PEEK 1
  15. #define _TRACK_TIME 0
  16. #define _TRACK_UPDATES 0
  17. #define _SHM_SCAN_INTERVAL_MS 100
  18. /////////////////////////////////////////////////////////////////////////////
  19. #define _INVALID_THREAD_ID 0
  20. /////////////////////////////////////////////////////////////////////////////
  21. // shmthread.h - Declarations:
  22. template<typename T, typename S>
  23. class CShmWatcher
  24. {
  25. public:
  26. CShmWatcher(HSHM hShm, T &rT, const void *pShm);
  27. virtual ~CShmWatcher(void);
  28. bool StartWatch(unsigned long nMsInterval = _SHM_SCAN_INTERVAL_MS);
  29. void StopWatch(void);
  30. static void* ShmWatchWorker(void *pParam);
  31. inline void Lock(void){
  32. (*m_pfnLock)(m_hShm);
  33. }
  34. inline void Unlock(void){
  35. (*m_pfnUnlock)(m_hShm);
  36. }
  37. void SetLockUnlockFunctions(PFN_GFA_IPC_LOCK_SHM pfnLock, PFN_GFA_IPC_UNLOCK_SHM pfnUnlock) {
  38. if(pfnLock && pfnUnlock)
  39. {
  40. Lock();
  41. PFN_GFA_IPC_UNLOCK_SHM pfnUlTmp = m_pfnUnlock;
  42. m_pfnLock = pfnLock;
  43. m_pfnUnlock = pfnUnlock;
  44. (*pfnUlTmp)(m_hShm);
  45. }
  46. else
  47. {
  48. Lock();
  49. PFN_GFA_IPC_UNLOCK_SHM pfnUlTmp = m_pfnUnlock;
  50. m_pfnLock = ::GfaIpcLockSHM;
  51. m_pfnUnlock = ::GfaIpcUnlockSHM;
  52. (*pfnUlTmp)(m_hShm);
  53. }
  54. }
  55. #if _SHM_SNEAK_PEEK
  56. inline bool ShmPeek(void){
  57. Lock();
  58. bool bRet = !!memcmp(m_pCache, m_pShm, sizeof(S));
  59. Unlock();
  60. return bRet;}
  61. inline void UpdateCache(void){
  62. Lock();
  63. memcpy(m_pCache, m_pShm, sizeof(S));
  64. Unlock();}
  65. #endif // _SHM_SNEAK_PEEK
  66. private:
  67. struct timespec m_tsInterval;
  68. pthread_t m_threadID;
  69. HSHM m_hShm;
  70. T &m_rT;
  71. S *m_pCache;
  72. const void *m_pShm;
  73. PFN_GFA_IPC_LOCK_SHM m_pfnLock;
  74. PFN_GFA_IPC_UNLOCK_SHM m_pfnUnlock;
  75. };
  76. /////////////////////////////////////////////////////////////////////////////
  77. /////////////////////////////////////////////////////////////////////////////
  78. /////////////////////////////////////////////////////////////////////////////
  79. template<typename T, typename S>
  80. CShmWatcher<T, S>::CShmWatcher(HSHM hShm, T &rT, const void *pShm) : m_threadID(_INVALID_THREAD_ID),
  81. m_hShm(hShm),
  82. m_rT(rT),
  83. m_pCache(NULL),
  84. m_pShm(pShm),
  85. m_pfnLock(::GfaIpcLockSHM),
  86. m_pfnUnlock(::GfaIpcUnlockSHM)
  87. {
  88. #if _SHM_SNEAK_PEEK
  89. if(m_pShm)
  90. {
  91. m_pCache = new S;
  92. memcpy(m_pCache, pShm, sizeof(S));
  93. }
  94. else
  95. {
  96. Q_ASSERT_X(false, "CShmWatcher::CShmWatcher", "Invalid SHM pointer!");
  97. }
  98. #endif // _SHM_SNEAK_PEEK
  99. }
  100. template<typename T, typename S>
  101. CShmWatcher<T, S>::~CShmWatcher(void)
  102. {
  103. StopWatch();
  104. #if _SHM_SNEAK_PEEK
  105. if(m_pCache)
  106. {
  107. delete m_pCache;
  108. m_pCache = NULL;
  109. }
  110. #endif // _SHM_SNEAK_PEEK
  111. }
  112. /////////////////////////////////////////////////////////////////////////////
  113. template<typename T, typename S>
  114. bool CShmWatcher<T, S>::StartWatch(unsigned long nMsInterval)
  115. {
  116. Lock();
  117. if(m_threadID != _INVALID_THREAD_ID)
  118. {
  119. Unlock();
  120. return true;
  121. }
  122. Unlock();
  123. m_tsInterval.tv_sec = nMsInterval / 1000;
  124. m_tsInterval.tv_nsec = (nMsInterval % 1000) * 1000000;
  125. bool bRet = !::pthread_create(&m_threadID, NULL, &CShmWatcher<T, S>::ShmWatchWorker, reinterpret_cast<void*>(this));
  126. if(!bRet)
  127. {
  128. m_threadID = _INVALID_THREAD_ID;
  129. qDebug() << "CShmWatcher::StartWatch failed!";
  130. }
  131. else
  132. {
  133. qDebug() << "CShmWatcher::StartWatch success!";
  134. }
  135. return bRet;
  136. }
  137. /////////////////////////////////////////////////////////////////////////////
  138. template<typename T, typename S>
  139. void CShmWatcher<T, S>::StopWatch(void)
  140. {
  141. pthread_t threadID;
  142. Lock();
  143. if((threadID = m_threadID) != _INVALID_THREAD_ID)
  144. m_threadID = _INVALID_THREAD_ID;
  145. Unlock();
  146. if(threadID != _INVALID_THREAD_ID)
  147. {
  148. ::pthread_cancel(threadID);
  149. ::pthread_join(threadID, NULL);
  150. qDebug() << "CShmWatcher::StopWatch: thread exit!";
  151. }
  152. }
  153. /////////////////////////////////////////////////////////////////////////////
  154. template<typename T, typename S>
  155. void* CShmWatcher<T, S>::ShmWatchWorker(void *pParam)
  156. {
  157. if(pParam)
  158. {
  159. #if _TRACK_UPDATES
  160. CHECK_UPDATE_SHM_RETVAL rv;
  161. #endif // _TRACK_UPDATES
  162. #if _TRACK_TIME
  163. struct timespec tsStart, tsEnd;
  164. #endif // _TRACK_TIME
  165. #if _SHM_SNEAK_PEEK
  166. bool bUpdt;
  167. #endif // _SHM_SNEAK_PEEK
  168. CShmWatcher<T, S>* pSelf = reinterpret_cast<CShmWatcher<T, S>*>(pParam);
  169. do
  170. {
  171. #if _TRACK_TIME
  172. unsigned long long nStart, nEnd;
  173. double fTime;
  174. ::clock_gettime(CLOCK_MONOTONIC, &tsStart);
  175. #endif // _TRACK_TIME
  176. #if _SHM_SNEAK_PEEK
  177. bUpdt = pSelf->ShmPeek();
  178. if(bUpdt)
  179. {
  180. #endif // _SHM_SNEAK_PEEK
  181. #if _TRACK_UPDATES
  182. rv.nRetval = pSelf->m_rT.CheckUpdateShm();
  183. #else // _TRACK_UPDATES
  184. pSelf->m_rT.CheckUpdateShm();
  185. #endif // _TRACK_UPDATES
  186. #if _SHM_SNEAK_PEEK
  187. pSelf->UpdateCache();
  188. }
  189. #if _TRACK_UPDATES
  190. else
  191. {
  192. rv.nRetval = 0;
  193. }
  194. #endif // _TRACK_UPDATES
  195. #endif // _SHM_SNEAK_PEEK
  196. #if _TRACK_TIME
  197. ::clock_gettime(CLOCK_MONOTONIC, &tsEnd);
  198. nStart = tsStart.tv_sec * 1000000000 + tsStart.tv_nsec;
  199. nEnd = tsEnd.tv_sec * 1000000000 + tsEnd.tv_nsec;
  200. fTime = (double)(nEnd - nStart) / 1000000.0;
  201. qDebug() << "CShmWatcher::ShmWatchWorker: Scan / Update time: - " << fTime << "ms";
  202. #endif // _TRACK_TIME
  203. #if _TRACK_UPDATES
  204. qDebug() << "CShmWatcher::ShmWatchWorker: Variables scanned / updated: - " << rv.nChecked << "/" << rv.nUpdated;
  205. #endif // _TRACK_UPDATES
  206. ::nanosleep(&pSelf->m_tsInterval, NULL);
  207. }
  208. while(true);
  209. pSelf->Lock();
  210. pSelf->m_threadID = _INVALID_THREAD_ID;
  211. pSelf->Unlock();
  212. qDebug() << "CShmWatcher::ShmWatchWorker: thread ended gracefully!";
  213. }
  214. return NULL;
  215. }
  216. /////////////////////////////////////////////////////////////////////////////
  217. #endif // !defined(AGD_SHMTHREAD_H__C09C5E02_A3A0_4171_BA2E_045C3FE0C05C__INCLUDED_)