libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmThread.h 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #ifndef cmThread_h
  4. #define cmThread_h
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. //( { file_desc:"Threads and thread safe containers." kw:[parallel] }
  9. typedef cmHandle_t cmThreadH_t;
  10. typedef unsigned cmThRC_t;
  11. enum
  12. {
  13. kOkThRC = cmOkRC, // 0
  14. kCreateFailThRC, // 1
  15. kDestroyFailThRC, // 2
  16. kTimeOutThRC, // 3
  17. kInvalidHandleThRC, // 4
  18. kLockFailThRC, // 5
  19. kUnlockFailThRC, // 6
  20. kCVarWaitFailThRC, // 7
  21. kCVarSignalFailThRC, // 8
  22. kBufFullThRC, // 9
  23. kBufEmptyThRC, // 10
  24. kBufTooSmallThRC // 11
  25. };
  26. typedef enum
  27. {
  28. kNotInitThId,
  29. kPausedThId,
  30. kRunningThId,
  31. kExitedThId
  32. } cmThStateId_t;
  33. // Return 'false' to indicate that the thread should terminate
  34. // otherwise return 'true'
  35. typedef bool (*cmThreadFunc_t)(void* param);
  36. extern cmThreadH_t cmThreadNullHandle;
  37. // Create a thread. The thread is automatically set to the 'paused' state.
  38. cmThRC_t cmThreadCreate( cmThreadH_t* hPtr, cmThreadFunc_t cmThreadFuncPtr, void* funcParam, cmRpt_t* rpt );
  39. // Release the resources associated with a thread previously created with cmThreadCreate().
  40. cmThRC_t cmThreadDestroy( cmThreadH_t* hPtr );
  41. enum
  42. {
  43. kPauseThFl = 0x01, // set to pause, clear to unpause
  44. kWaitThFl = 0x02 // set to wait for thread to pause/unpause prior to returning.
  45. };
  46. // Pause or unpause a thread. Set kWaitThFl to wait for the thread to be
  47. // paused or unpaused prior to returning.
  48. cmThRC_t cmThreadPause( cmThreadH_t h, unsigned cmdFlags );
  49. // Return the current thread state.
  50. cmThStateId_t cmThreadState( cmThreadH_t h );
  51. bool cmThreadIsValid( cmThreadH_t h);
  52. // The Pause time out gives the period in microseconds which the thread will
  53. // sleep while it is paused. In other words the thread will wake up
  54. // every 'pause time out micro-seconds' to check to see if it has been
  55. // requested to leave the paused state. Default:50000.
  56. unsigned cmThreadPauseTimeOutMicros( cmThreadH_t h );
  57. void cmThreadSetPauseTimeOutMicros( cmThreadH_t h, unsigned usecs );
  58. // The wait time out gives the length of time the thread should expect to
  59. // wait in order change states. This value should always be greater than
  60. // or equal to the pause time out and the expected length of time the
  61. // client callback function will run.
  62. // This timeout comes into play in two situations:
  63. // 1) This is the maximum length of time that cmThreadPause() will wait for
  64. // the thread to enter/leave the pause state when the kWaitThFl has been set.
  65. // If the thread does not enter/leave the pause state in this amount of time
  66. // then cmThreadPause() returns the error code kTimeOutThRC.
  67. // 2) This is the maximum length of time the cmThreadDestroy() wll wait for
  68. // the thread to enter the 'exited' state after being requested to destroy
  69. // itself. If this time period expires then cmThreadDestroy() returns
  70. // kTimeOutThRC.
  71. // Default:1000000.
  72. unsigned cmThreadWaitTimeOutMicros( cmThreadH_t h );
  73. void cmThreadSetWaitTimeOutMicros( cmThreadH_t h, unsigned usecs );
  74. void cmThreadTest( cmRpt_t* rpt );
  75. //)
  76. //( { label:cmThreadMutex file_desc:"Thread mutex object." kw[parallel]}
  77. //============================================================================
  78. typedef struct
  79. {
  80. void* h;
  81. } cmThreadMutexH_t;
  82. extern cmThreadMutexH_t kCmThreadMutexNULL;
  83. cmThRC_t cmThreadMutexCreate( cmThreadMutexH_t* hPtr, cmRpt_t* rpt );
  84. cmThRC_t cmThreadMutexDestroy( cmThreadMutexH_t* hPtr );
  85. cmThRC_t cmThreadMutexTryLock( cmThreadMutexH_t h, bool* lockFlPtr );
  86. cmThRC_t cmThreadMutexLock( cmThreadMutexH_t h );
  87. cmThRC_t cmThreadMutexUnlock( cmThreadMutexH_t h );
  88. bool cmThreadMutexIsValid( cmThreadMutexH_t h );
  89. // Set 'lockFl' if the function should lock the mutex prior to waiting.
  90. // If 'lockFl' is false then the function assumes the mutex is already locked
  91. // and directly waits. If 'lockFl' is set and the mutex is not already locked
  92. // then the result is undefined.
  93. cmThRC_t cmThreadMutexWaitOnCondVar( cmThreadMutexH_t h, bool lockFl );
  94. cmThRC_t cmThreadMutexSignalCondVar( cmThreadMutexH_t h );
  95. //)
  96. //( { label:cmTsQueue file_desc:"Thread safe message queue." kw[parallel]}
  97. //============================================================================
  98. // cmThread safe message queue.
  99. //
  100. // This object is intended as a way to serialize one-way
  101. // communication between multiple sender threads and one
  102. // receiver thread. The object is implemented as
  103. // a double buffer. One buffer acts as
  104. // an input queue the the other buffer acts as an
  105. // output queue. When the output queue is empty the buffers
  106. // are swapped. Any pending messages in the input queue
  107. // then become available to the receiver in the output queue.
  108. //
  109. // An internal mutex prevents the queue logic from becoming
  110. // corrupted. The mutex is locked during the entire enqueue
  111. // operation. The enqueue operation may therefore block its
  112. // thread while waiting for mutex access. The dequeue operation
  113. // only locks the mutex when the current output buffer is
  114. // empty, the input buffer contains messages, and the mutex
  115. // is not already locked. The mutex only remains locked for the
  116. // period of time necessary to switch the input and output
  117. // buffer pointers. The mutex is not locked during the actual
  118. // dequeue copy or transmit.
  119. //
  120. // Given this logic the dequeue thread should never
  121. // block because it only locks the mutex when it is not already
  122. // locked. The enqueue thread will only block when it happens to collide
  123. // with the dequeue buffer switch operation or an enqueue operation
  124. // from another thread. If it happens that there is only a single
  125. // sender thread then the sender will virtually never block because
  126. // the dequeue lock is only maintained for a very short period of time.
  127. //
  128. typedef cmHandle_t cmTsQueueH_t;
  129. extern cmTsQueueH_t cmTsQueueNullHandle;
  130. typedef cmRC_t (*cmTsQueueCb_t)(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr );
  131. // Set 'cbFunc' to NULL if the dequeue callback option will not be used.
  132. cmThRC_t cmTsQueueCreate( cmTsQueueH_t* hPtr, unsigned bufByteCnt, cmTsQueueCb_t cbFunc, void* cbArg, cmRpt_t* rpt );
  133. cmThRC_t cmTsQueueDestroy( cmTsQueueH_t* hPtr );
  134. // Set or clear the dequeue callback option after the queue was created.
  135. cmThRC_t cmTsQueueSetCallback( cmTsQueueH_t h, cmTsQueueCb_t cbFunc, void* cbArg );
  136. // Copy a msg into the queue. This function return kBufFullThRC if the buffer is full.
  137. // This interface allows the message to be formed from a concatenation of 'arrayCnt' segments.
  138. cmThRC_t cmTsQueueEnqueueSegMsg( cmTsQueueH_t h, const void* msgPtrArray[], unsigned msgByteCntArray[], unsigned arrayCnt );
  139. // Copy a msg onto the queue. This function is written in terms of cmTsQueueEnqueueSegMsg().
  140. cmThRC_t cmTsQueueEnqueueMsg( cmTsQueueH_t h, const void* dataPtr, unsigned byteCnt );
  141. // Prepend 'id' to the bytes contained in 'dataPtr[byteCnt]' and enqueue the resulting msg.
  142. // This function is written in terms of cmTesQueueEnqueueSegMsg().
  143. cmThRC_t cmTsQueueEnqueueIdMsg( cmTsQueueH_t h, unsigned id, const void* dataPtr, unsigned byteCnt );
  144. // Total size of the queue buffer.
  145. unsigned cmTsQueueAllocByteCount( cmTsQueueH_t h );
  146. // Bytes available to enqueue the next message.
  147. unsigned cmTsQueueAvailByteCount( cmTsQueueH_t h );
  148. // Remove one msg from the queue.
  149. // If 'dataPtr' is not NULL the msg is copied into the buffer it points to.
  150. // If 'cbFunc' in the earlier call to cmTsQueueCreate() was not NULL then
  151. // the msg is transmitted via the callback.
  152. // This function should only be called from the deque thread.
  153. cmThRC_t cmTsQueueDequeueMsg( cmTsQueueH_t h, void* dataPtr, unsigned byteCnt );
  154. // thQueueMsgWaiting() returns true if there is a msg available
  155. // to dequeue. This function should only be called from the
  156. // deque thread.
  157. bool cmTsQueueMsgWaiting( cmTsQueueH_t h );
  158. // Return the size in bytes of the next msg to dequeue or zero
  159. // if no msgs are waiting. The function should only be called from the
  160. // deque thread.
  161. unsigned cmTsQueueDequeueMsgByteCount( cmTsQueueH_t h );
  162. bool cmTsQueueIsValid( cmTsQueueH_t h);
  163. //)
  164. //( { label:cmTs1p1c file_desc:"Single producer/Single consumer non-blocking thread safe queue." kw[parallel]}
  165. //============================================================================
  166. // Single producer / Single consumer thread-safe queue.
  167. // These functions have identical semantics and return values
  168. // to the same named cmTsQueueXXXX() calls above.
  169. typedef cmHandle_t cmTs1p1cH_t;
  170. extern cmTs1p1cH_t cmTs1p1cNullHandle;
  171. cmThRC_t cmTs1p1cCreate( cmTs1p1cH_t* hPtr, unsigned bufByteCnt, cmTsQueueCb_t cbFunc, void* cbArg, cmRpt_t* rpt );
  172. cmThRC_t cmTs1p1cDestroy( cmTs1p1cH_t* hPtr );
  173. cmThRC_t cmTs1p1cSetCallback( cmTs1p1cH_t h, cmTsQueueCb_t cbFunc, void* cbArg );
  174. cmThRC_t cmTs1p1cEnqueueSegMsg( cmTs1p1cH_t h, const void* msgPtrArray[], unsigned msgByteCntArray[], unsigned arrayCnt );
  175. cmThRC_t cmTs1p1cEnqueueMsg( cmTs1p1cH_t h, const void* dataPtr, unsigned byteCnt );
  176. unsigned cmTs1p1cAllocByteCount( cmTs1p1cH_t h );
  177. unsigned cmTs1p1cAvailByteCount( cmTs1p1cH_t h );
  178. cmThRC_t cmTs1p1cDequeueMsg( cmTs1p1cH_t h, void* dataPtr, unsigned byteCnt );
  179. bool cmTs1p1cMsgWaiting( cmTs1p1cH_t h );
  180. unsigned cmTs1p1cDequeueMsgByteCount( cmTs1p1cH_t h );
  181. bool cmTs1p1cIsValid( cmTs1p1cH_t h );
  182. //)
  183. //( { label:cmThCAS file_desc:"Non-blocking primitive operations." kw[parallel]}
  184. //============================================================================
  185. // Thread safe compare-and-swap (actualy compare-and-test).
  186. // Returns true if the *addr==new when the function returns
  187. // otherwise returns false.
  188. bool cmThIntCAS( int* addr, int old, int neww );
  189. bool cmThUIntCAS( unsigned* addr, unsigned old, unsigned neww );
  190. bool cmThFloatCAS( float* addr, float old, float neww );
  191. // Note: voidPtrPtr is must really be a pointer to a pointer.
  192. bool cmThPtrCAS( void* voidPtrPtr, void* old, void* neww );
  193. // Thread safe increment and decrement implemented in terms of
  194. // cmThXXXCAS().
  195. void cmThIntIncr( int* addr, int incr );
  196. void cmThUIntIncr( unsigned* addr, unsigned incr );
  197. void cmThFloatIncr(float* addr, float incr );
  198. void cmThIntDecr( int* addr, int decr );
  199. void cmThUIntDecr( unsigned* addr, unsigned decr );
  200. void cmThFloatDecr(float* addr, float decr );
  201. //)
  202. //( { label:cmMp1c file_desc:"Multiple producer, single consumer non-blocking thread-safe queue." kw[parallel]}
  203. //============================================================================
  204. // Multiple producer / Single consumer thread-safe queue.
  205. // These functions have identical semantics and return values
  206. // to the same named cmTsQueueXXXX() calls above.
  207. typedef cmHandle_t cmTsMp1cH_t;
  208. extern cmTsMp1cH_t cmTsMp1cNullHandle;
  209. cmThRC_t cmTsMp1cCreate( cmTsMp1cH_t* hPtr, unsigned bufByteCnt, cmTsQueueCb_t cbFunc, void* cbArg, cmRpt_t* rpt );
  210. cmThRC_t cmTsMp1cDestroy( cmTsMp1cH_t* hPtr );
  211. void cmTsMp1cSetCbFunc( cmTsMp1cH_t h, cmTsQueueCb_t cbFunc, void* cbArg );
  212. cmTsQueueCb_t cmTsMp1cCbFunc( cmTsMp1cH_t h );
  213. void* cmTsMp1cCbArg( cmTsMp1cH_t h );
  214. cmThRC_t cmTsMp1cEnqueueSegMsg( cmTsMp1cH_t h, const void* msgPtrArray[], unsigned msgByteCntArray[], unsigned arrayCnt );
  215. cmThRC_t cmTsMp1cEnqueueMsg( cmTsMp1cH_t h, const void* dataPtr, unsigned byteCnt );
  216. unsigned cmTsMp1cAllocByteCount( cmTsMp1cH_t h );
  217. unsigned cmTsMp1cAvailByteCount( cmTsMp1cH_t h );
  218. cmThRC_t cmTsMp1cDequeueMsg( cmTsMp1cH_t h, void* dataPtr, unsigned byteCnt );
  219. bool cmTsMp1cMsgWaiting( cmTsMp1cH_t h );
  220. unsigned cmTsMp1cDequeueMsgByteCount( cmTsMp1cH_t h );
  221. bool cmTsMp1cIsValid( cmTsMp1cH_t h );
  222. void cmTsQueueTest( cmRpt_t* rpt );
  223. void cmTs1p1cTest( cmRpt_t* rpt );
  224. void cmTsMp1cTest( cmRpt_t* rpt );
  225. //)
  226. //( { label:cmSleep file_desc:"Sleep related functions." kw:[time] }
  227. // Sleep functions
  228. void cmSleepUs( unsigned microseconds );
  229. void cmSleepMs( unsigned milliseconds );
  230. //)
  231. #ifdef __cplusplus
  232. }
  233. #endif
  234. #endif