shmthread.h 5.2 KB

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