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.

cmTaskMgr.h 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #ifndef cmTaskMgr_h
  2. #define cmTaskMgr_h
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /*( { file_desc:"Task manager for controlling and monitoring tasks running in independent thread." kw:[parallel]}
  7. Usage:
  8. 1) Use cmTaskMgrInstall() to register a worker function
  9. (cmTaskMgrFunc_t) with the task manager.
  10. 2) Use cmTaskMgrCall() to queue a new instance of a
  11. task to run.
  12. 3) An internal scheduling program will start the task
  13. when there are less than 'maxActiveTaskCnt' running.
  14. This will occur when active tasks complete or are
  15. paused.
  16. When 'maxActiveTaskCnt' tasks are active and
  17. a previously paused task is unpaused the unpaused
  18. task will take precedence over tasks started after
  19. it and one of these new tasks will be deactivated.
  20. As tasks are pause/unpaused and activated/deactivated
  21. the number of active tasks may briefly exceed
  22. 'maxActiveTaskCnt'.
  23. 4) Once a task is instantiated the task manager
  24. will keep the client notified of the task status
  25. via callbacks to the cmTaskMgrStatusCb_t function.
  26. Status:
  27. kQueuedTmId - The task instance is waiting to be
  28. exectued in the task queue.
  29. kStartedTmId - The task has been made active and
  30. is running.
  31. kPausedTmId - The client sent a kPauseTmId to the
  32. task via cmTaskMgrCtl() and the task
  33. has been paused. The only way to
  34. restart the task is to send kStartTmId
  35. command.
  36. kDeactivatedTmId - The task was previously started but has
  37. now been deactivated by the system
  38. in an effort to keep the number of
  39. activate tasks at 'maxActiveTaskCnt'.
  40. kKilledTmId - The task was killed either by the client
  41. (via a cmTaskMgrCtl(kKillTmId)) or
  42. or by the system within cmTaskMgrClose()
  43. or cmTaskMgrDestroy().
  44. kCompletedTmId - The task has completed. Note that any
  45. task that gets queued is guaranteed to
  46. generate kCompletedTmId status callback.
  47. 5) Closing the task manager should follow a two step
  48. process. First all active tasks should be ended and then
  49. cmTaskMgrDestroy() should be called.
  50. Ending all active tasks can be accomplished by sending
  51. kill signals via cmTaskMgrCtl(), use of cmTaskMgrClose()
  52. or if all tasks are guaranteed to eventually end - waiting
  53. for the task count to go to zero (See cmTaskMgrActiveTaskCount()).
  54. Note that waiting for the task count to go to zero may be
  55. error prone unless one can guarantee that no tasks are
  56. queued or that the last task started has completed.
  57. */
  58. enum
  59. {
  60. kOkTmRC,
  61. kThreadFailTmRC,
  62. kInvalidArgTmRC,
  63. kOpFailTmRC,
  64. kQueueFailTmRC,
  65. kAssertFailTmRC,
  66. kTestFailTmRC
  67. };
  68. typedef cmRC_t cmTmRC_t;
  69. typedef cmHandle_t cmTaskMgrH_t;
  70. extern cmTaskMgrH_t cmTaskMgrNullHandle;
  71. typedef enum
  72. {
  73. kInvalidTmId,
  74. kQueuedTmId, // The task is waiting in the queue.
  75. kStartedTmId, // The task is running.
  76. kPausedTmId, // The task is paused.
  77. kDeactivatedTmId, // The task was temporarily deactivated by the system
  78. kCompletedTmId, // The task successfully completed.
  79. kKilledTmId // The task was killed by the client.
  80. } cmStatusTmId_t;
  81. typedef enum
  82. {
  83. kStatusTmId, // Task status updates. These are automatically sent by the system when the task instance changes state.
  84. kProgTmId, // Task progress update. The user function should increment the 'prog' toward 'progCnt'.
  85. kErrorTmId, // Error message ('cmTaskMgrStatusArg_t.prog' has error result code)
  86. kMsgTmId // Msg from a task instance in cmTaskMgrStatusArg_t.msg[msgByteCnt].
  87. } cmSelTmId_t;
  88. typedef enum
  89. {
  90. kStartTmId,
  91. kPauseTmId,
  92. kKillTmId
  93. } cmTaskMgrCtlId_t;
  94. typedef struct cmTaskMgrStatusArg_str
  95. {
  96. void* arg; // Client status arg. as passed to cmTaskMgrCreate().
  97. unsigned instId; // Task instance id of the task which generated the callback.
  98. cmSelTmId_t selId; // See cmSelTmId_t.
  99. cmStatusTmId_t statusId; // See cmStatusTmId_t.
  100. unsigned prog; // selId==kProgTmId (0<=prog<=cmTaskMgrFuncArg_t.progCnt) selId=kErrorTmid prog=error result code.
  101. const cmChar_t* text; // Used by kErrorTmId.
  102. const void* msg; // Used by kMsgTmId. msg[msgByteCnt]
  103. unsigned msgByteCnt; // Count of bytes in msg[].
  104. } cmTaskMgrStatusArg_t;
  105. typedef void (*cmTaskMgrStatusCb_t)( const cmTaskMgrStatusArg_t* status );
  106. typedef struct cmTaskMgrFuncArg_str
  107. {
  108. void* reserved;
  109. void* arg; // 'funcArg' provided by cmTaskMgrCall();
  110. unsigned argByteCnt; // 'funcArgByteCnt' provided by cmTaskMgrCall()
  111. unsigned instId; // Task instance id.
  112. cmTaskMgrStatusCb_t statusCb; // Status update function provided by cmTaskMgrCreate().
  113. void* statusCbArg; // Status update function arg. provided by cmTaskMgrCreate().
  114. unsigned progCnt; // Maximum expected value of cmTaskMgrStatusArg_t.prog during execution of this task instance.
  115. unsigned pauseSleepMs; // Length of time to sleep if the task receives a pause command.
  116. } cmTaskMgrFuncArg_t;
  117. // Task process function.
  118. typedef void (*cmTaskMgrFunc_t)(cmTaskMgrFuncArg_t* arg );
  119. // Task message receive function.
  120. typedef void (*cmTaskMgrRecv_t)(cmTaskMgrFuncArg_t* arg, const void* msg, unsigned msgByteCnt );
  121. // Allocate the task manager.
  122. cmTmRC_t cmTaskMgrCreate(
  123. cmCtx_t* ctx, //
  124. cmTaskMgrH_t* hp, //
  125. cmTaskMgrStatusCb_t statusCb, // Task status callbacks.
  126. void* statusCbArg, // Status callback arg
  127. unsigned maxActiveTaskCnt, // Max. number of active tasks (see Usage notes above.)
  128. unsigned queueByteCnt, // Size of task client->taskMgr and taskMgr->client msg queues.
  129. unsigned pauseSleepMs ); // Scheduler sleep time. (20-50ms)
  130. // Calling cmTaskMgrDestroy() will send a 'kill' control message
  131. // to any existing worker threads. The threads will shutdown
  132. // gracefully but the task they were computing will not be completed.
  133. cmTmRC_t cmTaskMgrDestroy( cmTaskMgrH_t* hp );
  134. enum
  135. {
  136. kKillQueuedTmFl = 0x01, // Kill any queued (otherwise queued tasks will be started)
  137. kTimeOutKillTmFl = 0x02 // KIll any instance not completed before returning
  138. };
  139. // Wait for the current task instances to complete.
  140. // Set 'timeOutMs' to the number of milliseconds to wait for the current tasks to complete.
  141. // Set kKillQueueTmFl to kill any queued tasks otherwise queued tasks will run as usual.
  142. // Set kRefuseCallTmFl to refuse to queue any new tasks following the return from this function.
  143. // Set kTimeOutKillTmFl to kill any tasks that are still running after timeOutMs has expired
  144. // otherwise these tasks will still be running when the function returns.
  145. cmTmRC_t cmTaskMgrClose( cmTaskMgrH_t h, unsigned flags, unsigned timeOutMs );
  146. // Return the current number of active tasks.
  147. unsigned cmTaskMgrActiveTaskCount( cmTaskMgrH_t h );
  148. // Return true if the task manager handle is valid.
  149. bool cmTaskMgrIsValid( cmTaskMgrH_t h );
  150. // Given a statusId return a the associated label.
  151. const cmChar_t* cmTaskMgrStatusIdToLabel( cmStatusTmId_t statusId );
  152. // Called by the client to give the task mgr an opportunity to execute
  153. // period functions from within the client thread. Note that 'statusCb()'
  154. // (as passed to cmTaskMgrCreate()) is only called within this function
  155. // This guarantees that all communication with the client occurs in the
  156. // clients thread.
  157. cmTmRC_t cmTaskMgrOnIdle( cmTaskMgrH_t h );
  158. // Pause/unpause the task mgr.
  159. // This function pauses/unpauses each worker thread and then the master thread.
  160. // If waitFl is set then the function will not return until each of
  161. // the threads has entered the requested state. If 'waitFl' is false
  162. // The function will wait for the worker threads to pause but will
  163. // only signal the master thread to pause before returning.
  164. bool cmTaskMgrIsEnabled( cmTaskMgrH_t h );
  165. cmTmRC_t cmTaskMgrEnable( cmTaskMgrH_t h, bool enableFl );
  166. // Install a task function and associate it with a label and unique id.
  167. cmTmRC_t cmTaskMgrInstall(
  168. cmTaskMgrH_t h,
  169. unsigned taskId, // Unique task id.
  170. const cmChar_t* label, // (optional) Task label
  171. cmTaskMgrFunc_t func, // Task worker function.
  172. cmTaskMgrRecv_t recv); // (optional) Task message receive function.
  173. // Queue a new task instance.
  174. // The 'queued' status callback occurs from inside this call.
  175. // If this function completes successfully then the client is
  176. // guaranteed to get both a 'kQueuedTmId' status update and
  177. // and a 'kCompletedTmId' update. Any per task instance cleanup
  178. // can therefore be triggered by the 'kCompleteTmId' status callback.
  179. cmTmRC_t cmTaskMgrCall(
  180. cmTaskMgrH_t h,
  181. unsigned taskId, // Task id of a task previously registered by cmTaskMgrInstall().
  182. void* funcArg, // The value assigned to cmTaskMgrFuncArg_t.arg for this instance.
  183. unsigned progCnt, // Max. expected progress value to be eventually reported by this task instances 'kProgTmId' progress updates.
  184. unsigned queueByteCnt, // Size of the client->task message buffer.
  185. const cmChar_t* label, // (optional) Instance label.
  186. unsigned* retInstIdPtr ); // (optional) Unique id assigned to this instance.
  187. // Start,pause, or kill a task instance.
  188. //
  189. // If a queued task is paused then it will remain at the front
  190. // of the queue and tasks behind it in the queue may be executed.
  191. // See the usage note above regarding the interaction between
  192. // pausing/unpausing, activating/deactivating and the
  193. // maxActiveTaskCnt parameter.
  194. //
  195. // Note that killing a task causes it to terminate quickly
  196. // but this does not imply that the task ends in an uncontrolled
  197. // manner. Even killed tasks properly release any resource they
  198. // may hold prior to ending. For long running tasks which do not
  199. // have a natural stopping point prior to the end of the client
  200. // process using the kill signal to end the task is both convenient
  201. // and efficient.
  202. //
  203. // Once a task is paused it is safe to directly interact with
  204. // the data space it has access to (e.g. cmTaskMgrFuncArg_t.funcArg).
  205. // This is true because the client has control over when the task
  206. // may start again via the cmStartTmId signal. Note that this is
  207. // not the case for deactivated signals. Deactivated signals may
  208. // be restarted at any time. Note however that it is possible to
  209. // pause a deactivated task in which case it's data space may
  210. // be accessed as soon as the client is notified that the task
  211. // has switched to the paused state.
  212. cmTmRC_t cmTaskMgrCtl( cmTaskMgrH_t h, unsigned instId, cmTaskMgrCtlId_t ctlId );
  213. // Get the status of a task.
  214. cmStatusTmId_t cmTaskMgrStatus( cmTaskMgrH_t h, unsigned instId );
  215. // Send a thread-safe msg to a task instance.
  216. cmTmRC_t cmTaskMgrSendMsg( cmTaskMgrH_t h, unsigned instId, const void* msg, unsigned msgByteCnt );
  217. const cmChar_t* cmTaskMgrTaskIdToLabel( cmTaskMgrH_t h, unsigned taskId );
  218. const cmChar_t* cmTaskMgrInstIdToLabel( cmTaskMgrH_t h, unsigned instId );
  219. // The following functions are only valid when the task has completed and
  220. // has a status of either kCompletedTmId.
  221. const void* cmTaskMgrResult( cmTaskMgrH_t h, unsigned instId );
  222. unsigned cmTaskMgrResultByteCount( cmTaskMgrH_t h, unsigned instId );
  223. void* cmTaskMgrFuncArg( cmTaskMgrH_t h, unsigned instId );
  224. cmTmRC_t cmTaskMgrInstDelete( cmTaskMgrH_t h, unsigned instId );
  225. // -----------------------------------------------------------------------------------
  226. // Worker thread helper functions.
  227. //
  228. // These functions should only be called from inside the client supplied
  229. // worker function (cmTaskMgrFuncArg_t).
  230. //
  231. // There are two thread-safe methods the worker thread can use to receive
  232. // raw byte messages from the client.
  233. //
  234. // 1. Assign a cmTaskMgrRecv_t function at task installation
  235. // (See cmTaskMgrInstall().) This callback will be invoked from inside
  236. // cmTaskMgrWorkerHandleCommand()
  237. // if a client message is found to be waiting. When this occurs the
  238. // worker helper function will return kRecvTmwRC.
  239. //
  240. // 2. If the task was not assigned a cmTaskMgrRect_t function then
  241. // the worker should notice when
  242. // cmTaskMgrWorkerHandleCommand() returns cmRecvTmwRC. When this occurs
  243. // it should call cmTaskMgrMsgRecv() to copy the message into a
  244. // locally allocated buffer. cmTaskMgrWorkerMsgByteCount() can
  245. // be called to find out the size of the message and therefore
  246. // the minimum size of the copy destination buffer.
  247. typedef enum
  248. {
  249. kOkTmwRC,
  250. kStopTmwRC,
  251. kRecvTmwRC
  252. } cmTmWorkerRC_t;
  253. // The instance function cmTaskMgrFunc_t must poll this
  254. // function to respond to incoming commands and messages.
  255. // The polling rate should be determined by the application to
  256. // trade-off the cost of the poll versus the command execution
  257. // latency. Checking every 20 to 100 milliseconcds is probably
  258. // about right.
  259. // If the function returns 'kStopTmwRC' then the function has received
  260. // a kKillCtlId and should release any resources and return immediately.
  261. // If the function returns 'kRecvTmwRC' and has not registered a
  262. // cmTaskMgrRecv_t function then it should call cmTaskMgrWorkerRecv()
  263. // to pick up an incoming message from the client.
  264. // If the function returns 'kRecvTmwRC' and does have a registered
  265. // cmTaskMgrRecv_t function then a new message was received by the
  266. // cmTaskMGrRecv_t function.
  267. cmTmWorkerRC_t cmTaskMgrWorkerHandleCommand( cmTaskMgrFuncArg_t* a );
  268. // Send a task status update to the client.
  269. //cmTmRC_t cmTaskMgrWorkerSendStatus( cmTaskMgrFuncArg_t* a, cmStatusTmId_t statusId );
  270. // Send a progress update to the client.
  271. cmTmRC_t cmTaskMgrWorkerSendProgress( cmTaskMgrFuncArg_t* a, unsigned prog, const cmChar_t* text );
  272. cmTmRC_t cmTaskMgrWorkerSendProgressV( cmTaskMgrFuncArg_t* a, unsigned prog, const cmChar_t* fmt, va_list vl );
  273. cmTmRC_t cmTaskMgrWorkerSendProgressF( cmTaskMgrFuncArg_t* a, unsigned prog, const cmChar_t* fmt, ... );
  274. // Send an error message to the client. The result code is application
  275. // dependent. These function return 'rc' as does cmErrMsg().
  276. cmTmRC_t cmTaskMgrWorkerError( cmTaskMgrFuncArg_t* a, unsigned rc, const cmChar_t* text );
  277. cmTmRC_t cmTaskMgrWorkerErrorV( cmTaskMgrFuncArg_t* a, unsigned rc, const cmChar_t* fmt, va_list vl );
  278. cmTmRC_t cmTaskMgrWorkerErrorF( cmTaskMgrFuncArg_t* a, unsigned rc, const cmChar_t* fmt, ... );
  279. // Set the internal result buffer for this instance.
  280. // This is a convenient way to assign a final result to a instance
  281. // which can eventually be picked up by cmTaskMgrResult()
  282. // after the worker has officially completed. Alternatively the
  283. // result of the worker computation can be returned using
  284. // cmTaskMgrWorkerMsgSend().
  285. cmTmRC_t cmTaskMgrWorkerSetResult( cmTaskMgrFuncArg_t* a, void* result, unsigned resultByteCnt );
  286. // Get the size of an incoming message sent to this task instance
  287. // from the client. Use cmTaskMgrWorkerMsgRecv() to get
  288. // the msg. contents.
  289. unsigned cmTaskMgrWorkerMsgByteCount( cmTaskMgrFuncArg_t* a );
  290. // Copy a msg from the client into buf[bufByteCnt] and
  291. // return the count of bytes copied into buf[bufByteCnt] or cmInvalidCnt
  292. // if the buf[] was too small. This function is only used when
  293. // the task did notregister a cmTaskMgrRecv_t with cmTaskMgrInstall().
  294. // cmTaskMgrWorkerMsgByteCount() returns the minimum required size of buf[].
  295. unsigned cmTaskMgrWorkerMsgRecv( cmTaskMgrFuncArg_t* a, void* buf, unsigned bufByteCnt );
  296. // Send a generic msg to the client.
  297. cmTmWorkerRC_t cmTaskMgrWorkerMsgSend( cmTaskMgrFuncArg_t* a, const void* buf, unsigned bufByteCnt );
  298. cmTmRC_t cmTaskMgrTest(cmCtx_t* ctx);
  299. //)
  300. #ifdef __cplusplus
  301. }
  302. #endif
  303. #endif