os_q.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. /*
  2. ************************************************************************************************************************
  3. * uC/OS-III
  4. * The Real-Time Kernel
  5. *
  6. * (c) Copyright 2009-2011; Micrium, Inc.; Weston, FL
  7. * All rights reserved. Protected by international copyright laws.
  8. *
  9. * MESSAGE QUEUE MANAGEMENT
  10. *
  11. * File : OS_Q.C
  12. * By : JJL
  13. * Version : V3.02.00
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
  18. * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
  19. * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
  20. * application/product. We provide ALL the source code for your convenience and to help you
  21. * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
  22. * it commercially without paying a licensing fee.
  23. *
  24. * Knowledge of the source code may NOT be used to develop a similar product.
  25. *
  26. * Please help us continue to provide the embedded community with the finest software available.
  27. * Your honesty is greatly appreciated.
  28. *
  29. * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
  30. ************************************************************************************************************************
  31. */
  32. #include <os.h>
  33. #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
  34. const CPU_CHAR *os_q__c = "$Id: $";
  35. #endif
  36. #if OS_CFG_Q_EN > 0u
  37. /*
  38. ************************************************************************************************************************
  39. * CREATE A MESSAGE QUEUE
  40. *
  41. * Description: This function is called by your application to create a message queue. Message queues MUST be created
  42. * before they can be used.
  43. *
  44. * Arguments : p_q is a pointer to the message queue
  45. *
  46. * p_name is a pointer to an ASCII string that will be used to name the message queue
  47. *
  48. * max_qty indicates the maximum size of the message queue (must be non-zero). Note that it's also not
  49. * possible to have a size higher than the maximum number of OS_MSGs available.
  50. *
  51. * p_err is a pointer to a variable that will contain an error code returned by this function.
  52. *
  53. * OS_ERR_NONE the call was successful
  54. * OS_ERR_CREATE_ISR can't create from an ISR
  55. * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the Queue after you called
  56. * OSSafetyCriticalStart().
  57. * OS_ERR_NAME if 'p_name' is a NULL pointer
  58. * OS_ERR_OBJ_CREATED if the message queue has already been created
  59. * OS_ERR_OBJ_PTR_NULL if you passed a NULL pointer for 'p_q'
  60. * OS_ERR_Q_SIZE if the size you specified is 0
  61. *
  62. * Returns : none
  63. ************************************************************************************************************************
  64. */
  65. void OSQCreate (OS_Q *p_q,
  66. CPU_CHAR *p_name,
  67. OS_MSG_QTY max_qty,
  68. OS_ERR *p_err)
  69. {
  70. CPU_SR_ALLOC();
  71. #ifdef OS_SAFETY_CRITICAL
  72. if (p_err == (OS_ERR *)0) {
  73. OS_SAFETY_CRITICAL_EXCEPTION();
  74. return;
  75. }
  76. #endif
  77. #ifdef OS_SAFETY_CRITICAL_IEC61508
  78. if (OSSafetyCriticalStartFlag == DEF_TRUE) {
  79. *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  80. return;
  81. }
  82. #endif
  83. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  84. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to be called from an ISR */
  85. *p_err = OS_ERR_CREATE_ISR;
  86. return;
  87. }
  88. #endif
  89. #if OS_CFG_ARG_CHK_EN > 0u
  90. if (p_q == (OS_Q *)0) { /* Validate arguments */
  91. *p_err = OS_ERR_OBJ_PTR_NULL;
  92. return;
  93. }
  94. if (max_qty == (OS_MSG_QTY)0) { /* Cannot specify a zero size queue */
  95. *p_err = OS_ERR_Q_SIZE;
  96. return;
  97. }
  98. #endif
  99. OS_CRITICAL_ENTER();
  100. p_q->Type = OS_OBJ_TYPE_Q; /* Mark the data structure as a message queue */
  101. p_q->NamePtr = p_name;
  102. OS_MsgQInit(&p_q->MsgQ, /* Initialize the queue */
  103. max_qty);
  104. OS_PendListInit(&p_q->PendList); /* Initialize the waiting list */
  105. #if OS_CFG_DBG_EN > 0u
  106. OS_QDbgListAdd(p_q);
  107. #endif
  108. OSQQty++; /* One more queue created */
  109. OS_CRITICAL_EXIT();
  110. *p_err = OS_ERR_NONE;
  111. }
  112. /*$PAGE*/
  113. /*
  114. ************************************************************************************************************************
  115. * DELETE A MESSAGE QUEUE
  116. *
  117. * Description: This function deletes a message queue and readies all tasks pending on the queue.
  118. *
  119. * Arguments : p_q is a pointer to the message queue you want to delete
  120. *
  121. * opt determines delete options as follows:
  122. *
  123. * OS_OPT_DEL_NO_PEND Delete the queue ONLY if no task pending
  124. * OS_OPT_DEL_ALWAYS Deletes the queue even if tasks are waiting.
  125. * In this case, all the tasks pending will be readied.
  126. *
  127. * p_err is a pointer to a variable that will contain an error code returned by this function.
  128. *
  129. * OS_ERR_NONE The call was successful and the queue was deleted
  130. * OS_ERR_DEL_ISR If you tried to delete the queue from an ISR
  131. * OS_ERR_OBJ_PTR_NULL if you pass a NULL pointer for 'p_q'
  132. * OS_ERR_OBJ_TYPE if the message queue was not created
  133. * OS_ERR_OPT_INVALID An invalid option was specified
  134. * OS_ERR_TASK_WAITING One or more tasks were waiting on the queue
  135. *
  136. * Returns : == 0 if no tasks were waiting on the queue, or upon error.
  137. * > 0 if one or more tasks waiting on the queue are now readied and informed.
  138. *
  139. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the queue MUST
  140. * check the return code of OSQPend().
  141. *
  142. * 2) OSQAccept() callers will not know that the intended queue has been deleted.
  143. *
  144. * 3) Because ALL tasks pending on the queue will be readied, you MUST be careful in applications where the
  145. * queue is used for mutual exclusion because the resource(s) will no longer be guarded by the queue.
  146. ************************************************************************************************************************
  147. */
  148. #if OS_CFG_Q_DEL_EN > 0u
  149. OS_OBJ_QTY OSQDel (OS_Q *p_q,
  150. OS_OPT opt,
  151. OS_ERR *p_err)
  152. {
  153. OS_OBJ_QTY cnt;
  154. OS_OBJ_QTY nbr_tasks;
  155. OS_PEND_DATA *p_pend_data;
  156. OS_PEND_LIST *p_pend_list;
  157. OS_TCB *p_tcb;
  158. CPU_TS ts;
  159. CPU_SR_ALLOC();
  160. #ifdef OS_SAFETY_CRITICAL
  161. if (p_err == (OS_ERR *)0) {
  162. OS_SAFETY_CRITICAL_EXCEPTION();
  163. return ((OS_OBJ_QTY)0);
  164. }
  165. #endif
  166. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  167. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't delete a message queue from an ISR */
  168. *p_err = OS_ERR_DEL_ISR;
  169. return ((OS_OBJ_QTY)0);
  170. }
  171. #endif
  172. #if OS_CFG_ARG_CHK_EN > 0u
  173. if (p_q == (OS_Q *)0) { /* Validate arguments */
  174. *p_err = OS_ERR_OBJ_PTR_NULL;
  175. return ((OS_OBJ_QTY)0);
  176. }
  177. #endif
  178. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  179. if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
  180. *p_err = OS_ERR_OBJ_TYPE;
  181. return ((OS_OBJ_QTY)0);
  182. }
  183. #endif
  184. CPU_CRITICAL_ENTER();
  185. p_pend_list = &p_q->PendList;
  186. cnt = p_pend_list->NbrEntries;
  187. nbr_tasks = cnt;
  188. switch (opt) {
  189. case OS_OPT_DEL_NO_PEND: /* Delete message queue only if no task waiting */
  190. if (nbr_tasks == (OS_OBJ_QTY)0) {
  191. #if OS_CFG_DBG_EN > 0u
  192. OS_QDbgListRemove(p_q);
  193. #endif
  194. OSQQty--;
  195. OS_QClr(p_q);
  196. CPU_CRITICAL_EXIT();
  197. *p_err = OS_ERR_NONE;
  198. } else {
  199. CPU_CRITICAL_EXIT();
  200. *p_err = OS_ERR_TASK_WAITING;
  201. }
  202. break;
  203. case OS_OPT_DEL_ALWAYS: /* Always delete the message queue */
  204. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  205. ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
  206. while (cnt > 0u) { /* Remove all tasks from the pend list */
  207. p_pend_data = p_pend_list->HeadPtr;
  208. p_tcb = p_pend_data->TCBPtr;
  209. OS_PendObjDel((OS_PEND_OBJ *)((void *)p_q),
  210. p_tcb,
  211. ts);
  212. cnt--;
  213. }
  214. #if OS_CFG_DBG_EN > 0u
  215. OS_QDbgListRemove(p_q);
  216. #endif
  217. OSQQty--;
  218. OS_QClr(p_q);
  219. OS_CRITICAL_EXIT_NO_SCHED();
  220. OSSched(); /* Find highest priority task ready to run */
  221. *p_err = OS_ERR_NONE;
  222. break;
  223. default:
  224. CPU_CRITICAL_EXIT();
  225. *p_err = OS_ERR_OPT_INVALID;
  226. break;
  227. }
  228. return (nbr_tasks);
  229. }
  230. #endif
  231. /*$PAGE*/
  232. /*
  233. ************************************************************************************************************************
  234. * FLUSH QUEUE
  235. *
  236. * Description : This function is used to flush the contents of the message queue.
  237. *
  238. * Arguments : p_q is a pointer to the message queue to flush
  239. *
  240. * p_err is a pointer to a variable that will contain an error code returned by this function.
  241. *
  242. * OS_ERR_NONE upon success
  243. * OS_ERR_FLUSH_ISR if you called this function from an ISR
  244. * OS_ERR_OBJ_PTR_NULL If you passed a NULL pointer for 'p_q'
  245. * OS_ERR_OBJ_TYPE If you didn't create the message queue
  246. *
  247. * Returns : The number of entries freed from the queue
  248. *
  249. * Note(s) : 1) You should use this function with great care because, when to flush the queue, you LOOSE the
  250. * references to what the queue entries are pointing to and thus, you could cause 'memory leaks'. In
  251. * other words, the data you are pointing to that's being referenced by the queue entries should, most
  252. * likely, need to be de-allocated (i.e. freed).
  253. ************************************************************************************************************************
  254. */
  255. #if OS_CFG_Q_FLUSH_EN > 0u
  256. OS_MSG_QTY OSQFlush (OS_Q *p_q,
  257. OS_ERR *p_err)
  258. {
  259. OS_MSG_QTY entries;
  260. CPU_SR_ALLOC();
  261. #ifdef OS_SAFETY_CRITICAL
  262. if (p_err == (OS_ERR *)0) {
  263. OS_SAFETY_CRITICAL_EXCEPTION();
  264. return ((OS_MSG_QTY)0);
  265. }
  266. #endif
  267. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  268. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't flush a message queue from an ISR */
  269. *p_err = OS_ERR_FLUSH_ISR;
  270. return ((OS_MSG_QTY)0);
  271. }
  272. #endif
  273. #if OS_CFG_ARG_CHK_EN > 0u
  274. if (p_q == (OS_Q *)0) { /* Validate arguments */
  275. *p_err = OS_ERR_OBJ_PTR_NULL;
  276. return ((OS_MSG_QTY)0);
  277. }
  278. #endif
  279. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  280. if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
  281. *p_err = OS_ERR_OBJ_TYPE;
  282. return ((OS_MSG_QTY)0);
  283. }
  284. #endif
  285. OS_CRITICAL_ENTER();
  286. entries = OS_MsgQFreeAll(&p_q->MsgQ); /* Return all OS_MSGs to the OS_MSG pool */
  287. OS_CRITICAL_EXIT();
  288. *p_err = OS_ERR_NONE;
  289. return ((OS_MSG_QTY)entries);
  290. }
  291. #endif
  292. /*$PAGE*/
  293. /*
  294. ************************************************************************************************************************
  295. * PEND ON A QUEUE FOR A MESSAGE
  296. *
  297. * Description: This function waits for a message to be sent to a queue
  298. *
  299. * Arguments : p_q is a pointer to the message queue
  300. *
  301. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a
  302. * message to arrive at the queue up to the amount of time specified by this argument. If you
  303. * specify 0, however, your task will wait forever at the specified queue or, until a message
  304. * arrives.
  305. *
  306. * opt determines whether the user wants to block if the queue is empty or not:
  307. *
  308. * OS_OPT_PEND_BLOCKING
  309. * OS_OPT_PEND_NON_BLOCKING
  310. *
  311. * p_msg_size is a pointer to a variable that will receive the size of the message
  312. *
  313. * p_ts is a pointer to a variable that will receive the timestamp of when the message was
  314. * received, pend aborted or the message queue deleted, If you pass a NULL pointer (i.e.
  315. * (CPU_TS *)0) then you will not get the timestamp. In other words, passing a NULL pointer
  316. * is valid and indicates that you don't need the timestamp.
  317. *
  318. * p_err is a pointer to a variable that will contain an error code returned by this function.
  319. *
  320. * OS_ERR_NONE The call was successful and your task received a message.
  321. * OS_ERR_OBJ_PTR_NULL if you pass a NULL pointer for 'p_q'
  322. * OS_ERR_OBJ_TYPE if the message queue was not created
  323. * OS_ERR_PEND_ABORT the pend was aborted
  324. * OS_ERR_PEND_ISR if you called this function from an ISR
  325. * OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the queue was not empty
  326. * OS_ERR_SCHED_LOCKED the scheduler is locked
  327. * OS_ERR_TIMEOUT A message was not received within the specified timeout
  328. * would lead to a suspension.
  329. *
  330. * Returns : != (void *)0 is a pointer to the message received
  331. * == (void *)0 if you received a NULL pointer message or,
  332. * if no message was received or,
  333. * if 'p_q' is a NULL pointer or,
  334. * if you didn't pass a pointer to a queue.
  335. ************************************************************************************************************************
  336. */
  337. void *OSQPend (OS_Q *p_q,
  338. OS_TICK timeout,
  339. OS_OPT opt,
  340. OS_MSG_SIZE *p_msg_size,
  341. CPU_TS *p_ts,
  342. OS_ERR *p_err)
  343. {
  344. OS_PEND_DATA pend_data;
  345. void *p_void;
  346. CPU_SR_ALLOC();
  347. #ifdef OS_SAFETY_CRITICAL
  348. if (p_err == (OS_ERR *)0) {
  349. OS_SAFETY_CRITICAL_EXCEPTION();
  350. return ((void *)0);
  351. }
  352. #endif
  353. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  354. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
  355. *p_err = OS_ERR_PEND_ISR;
  356. return ((void *)0);
  357. }
  358. #endif
  359. #if OS_CFG_ARG_CHK_EN > 0u
  360. if (p_q == (OS_Q *)0) { /* Validate arguments */
  361. *p_err = OS_ERR_OBJ_PTR_NULL;
  362. return ((void *)0);
  363. }
  364. if (p_msg_size == (OS_MSG_SIZE *)0) {
  365. *p_err = OS_ERR_PTR_INVALID;
  366. return ((void *)0);
  367. }
  368. switch (opt) {
  369. case OS_OPT_PEND_BLOCKING:
  370. case OS_OPT_PEND_NON_BLOCKING:
  371. break;
  372. default:
  373. *p_err = OS_ERR_OPT_INVALID;
  374. return ((void *)0);
  375. }
  376. #endif
  377. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  378. if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
  379. *p_err = OS_ERR_OBJ_TYPE;
  380. return ((void *)0);
  381. }
  382. #endif
  383. if (p_ts != (CPU_TS *)0) {
  384. *p_ts = (CPU_TS )0; /* Initialize the returned timestamp */
  385. }
  386. CPU_CRITICAL_ENTER();
  387. p_void = OS_MsgQGet(&p_q->MsgQ, /* Any message waiting in the message queue? */
  388. p_msg_size,
  389. p_ts,
  390. p_err);
  391. if (*p_err == OS_ERR_NONE) {
  392. CPU_CRITICAL_EXIT();
  393. return (p_void); /* Yes, Return message received */
  394. }
  395. if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */
  396. CPU_CRITICAL_EXIT();
  397. *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */
  398. return ((void *)0);
  399. } else {
  400. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */
  401. CPU_CRITICAL_EXIT();
  402. *p_err = OS_ERR_SCHED_LOCKED;
  403. return ((void *)0);
  404. }
  405. }
  406. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
  407. OS_Pend(&pend_data, /* Block task pending on Message Queue */
  408. (OS_PEND_OBJ *)((void *)p_q),
  409. OS_TASK_PEND_ON_Q,
  410. timeout);
  411. OS_CRITICAL_EXIT_NO_SCHED();
  412. OSSched(); /* Find the next highest priority task ready to run */
  413. CPU_CRITICAL_ENTER();
  414. switch (OSTCBCurPtr->PendStatus) {
  415. case OS_STATUS_PEND_OK: /* Extract message from TCB (Put there by Post) */
  416. p_void = OSTCBCurPtr->MsgPtr;
  417. *p_msg_size = OSTCBCurPtr->MsgSize;
  418. if (p_ts != (CPU_TS *)0) {
  419. *p_ts = OSTCBCurPtr->TS;
  420. }
  421. *p_err = OS_ERR_NONE;
  422. break;
  423. case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */
  424. p_void = (void *)0;
  425. *p_msg_size = (OS_MSG_SIZE)0;
  426. if (p_ts != (CPU_TS *)0) {
  427. *p_ts = OSTCBCurPtr->TS;
  428. }
  429. *p_err = OS_ERR_PEND_ABORT;
  430. break;
  431. case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get event within TO */
  432. p_void = (void *)0;
  433. *p_msg_size = (OS_MSG_SIZE)0;
  434. if (p_ts != (CPU_TS *)0) {
  435. *p_ts = (CPU_TS )0;
  436. }
  437. *p_err = OS_ERR_TIMEOUT;
  438. break;
  439. case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */
  440. p_void = (void *)0;
  441. *p_msg_size = (OS_MSG_SIZE)0;
  442. if (p_ts != (CPU_TS *)0) {
  443. *p_ts = OSTCBCurPtr->TS;
  444. }
  445. *p_err = OS_ERR_OBJ_DEL;
  446. break;
  447. default:
  448. p_void = (void *)0;
  449. *p_msg_size = (OS_MSG_SIZE)0;
  450. *p_err = OS_ERR_STATUS_INVALID;
  451. break;
  452. }
  453. CPU_CRITICAL_EXIT();
  454. return (p_void);
  455. }
  456. /*$PAGE*/
  457. /*
  458. ************************************************************************************************************************
  459. * ABORT WAITING ON A MESSAGE QUEUE
  460. *
  461. * Description: This function aborts & readies any tasks currently waiting on a queue. This function should be used to
  462. * fault-abort the wait on the queue, rather than to normally signal the queue via OSQPost().
  463. *
  464. * Arguments : p_q is a pointer to the message queue
  465. *
  466. * opt determines the type of ABORT performed:
  467. *
  468. * OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the queue
  469. * OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the queue
  470. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  471. *
  472. * p_err is a pointer to a variable that will contain an error code returned by this function.
  473. *
  474. * OS_ERR_NONE At least one task waiting on the queue was readied and
  475. * informed of the aborted wait; check return value for the
  476. * number of tasks whose wait on the queue was aborted.
  477. * OS_ERR_OPT_INVALID if you specified an invalid option
  478. * OS_ERR_OBJ_PTR_NULL if you pass a NULL pointer for 'p_q'
  479. * OS_ERR_OBJ_TYPE if the message queue was not created
  480. * OS_ERR_PEND_ABORT_ISR If this function was called from an ISR
  481. * OS_ERR_PEND_ABORT_NONE No task were pending
  482. *
  483. * Returns : == 0 if no tasks were waiting on the queue, or upon error.
  484. * > 0 if one or more tasks waiting on the queue are now readied and informed.
  485. ************************************************************************************************************************
  486. */
  487. #if OS_CFG_Q_PEND_ABORT_EN > 0u
  488. OS_OBJ_QTY OSQPendAbort (OS_Q *p_q,
  489. OS_OPT opt,
  490. OS_ERR *p_err)
  491. {
  492. OS_PEND_LIST *p_pend_list;
  493. OS_TCB *p_tcb;
  494. CPU_TS ts;
  495. OS_OBJ_QTY nbr_tasks;
  496. CPU_SR_ALLOC();
  497. #ifdef OS_SAFETY_CRITICAL
  498. if (p_err == (OS_ERR *)0) {
  499. OS_SAFETY_CRITICAL_EXCEPTION();
  500. return ((OS_OBJ_QTY)0u);
  501. }
  502. #endif
  503. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  504. if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to Pend Abort from an ISR */
  505. *p_err = OS_ERR_PEND_ABORT_ISR;
  506. return ((OS_OBJ_QTY)0u);
  507. }
  508. #endif
  509. #if OS_CFG_ARG_CHK_EN > 0u
  510. if (p_q == (OS_Q *)0) { /* Validate 'p_q' */
  511. *p_err = OS_ERR_OBJ_PTR_NULL;
  512. return ((OS_OBJ_QTY)0u);
  513. }
  514. switch (opt) { /* Validate 'opt' */
  515. case OS_OPT_PEND_ABORT_1:
  516. case OS_OPT_PEND_ABORT_ALL:
  517. break;
  518. default:
  519. *p_err = OS_ERR_OPT_INVALID;
  520. return ((OS_OBJ_QTY)0u);
  521. }
  522. #endif
  523. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  524. if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure queue was created */
  525. *p_err = OS_ERR_OBJ_TYPE;
  526. return ((OS_OBJ_QTY)0u);
  527. }
  528. #endif
  529. CPU_CRITICAL_ENTER();
  530. p_pend_list = &p_q->PendList;
  531. if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0u) { /* Any task waiting on queue? */
  532. CPU_CRITICAL_EXIT(); /* No */
  533. *p_err = OS_ERR_PEND_ABORT_NONE;
  534. return ((OS_OBJ_QTY)0u);
  535. }
  536. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  537. nbr_tasks = 0u;
  538. ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
  539. while (p_pend_list->NbrEntries > (OS_OBJ_QTY)0u) {
  540. p_tcb = p_pend_list->HeadPtr->TCBPtr;
  541. OS_PendAbort((OS_PEND_OBJ *)((void *)p_q),
  542. p_tcb,
  543. ts);
  544. nbr_tasks++;
  545. if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */
  546. break; /* No */
  547. }
  548. }
  549. OS_CRITICAL_EXIT_NO_SCHED();
  550. if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0u) {
  551. OSSched(); /* Run the scheduler */
  552. }
  553. *p_err = OS_ERR_NONE;
  554. return (nbr_tasks);
  555. }
  556. #endif
  557. /*$PAGE*/
  558. /*
  559. ************************************************************************************************************************
  560. * POST MESSAGE TO A QUEUE
  561. *
  562. * Description: This function sends a message to a queue. With the 'opt' argument, you can specify whether the message
  563. * is broadcast to all waiting tasks and/or whether you post the message to the front of the queue (LIFO)
  564. * or normally (FIFO) at the end of the queue.
  565. *
  566. * Arguments : p_q is a pointer to a message queue that must have been created by OSQCreate().
  567. *
  568. * p_void is a pointer to the message to send.
  569. *
  570. * msg_size specifies the size of the message (in bytes)
  571. *
  572. * opt determines the type of POST performed:
  573. *
  574. * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the queue. This option
  575. * can be added to either OS_OPT_POST_FIFO or OS_OPT_POST_LIFO
  576. * OS_OPT_POST_FIFO POST message to end of queue (FIFO) and wake up a single
  577. * waiting task.
  578. * OS_OPT_POST_LIFO POST message to the front of the queue (LIFO) and wake up
  579. * a single waiting task.
  580. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  581. *
  582. * Note(s): 1) OS_OPT_POST_NO_SCHED can be added (or OR'd) with one of the other options.
  583. * 2) OS_OPT_POST_ALL can be added (or OR'd) with one of the other options.
  584. * 3) Possible combination of options are:
  585. *
  586. * OS_OPT_POST_FIFO
  587. * OS_OPT_POST_LIFO
  588. * OS_OPT_POST_FIFO + OS_OPT_POST_ALL
  589. * OS_OPT_POST_LIFO + OS_OPT_POST_ALL
  590. * OS_OPT_POST_FIFO + OS_OPT_POST_NO_SCHED
  591. * OS_OPT_POST_LIFO + OS_OPT_POST_NO_SCHED
  592. * OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED
  593. * OS_OPT_POST_LIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED
  594. *
  595. * p_err is a pointer to a variable that will contain an error code returned by this function.
  596. *
  597. * OS_ERR_NONE The call was successful and the message was sent
  598. * OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs to use to place the message into
  599. * OS_ERR_OBJ_PTR_NULL If 'p_q' is a NULL pointer
  600. * OS_ERR_OBJ_TYPE If the message queue was not initialized
  601. * OS_ERR_Q_MAX If the queue is full
  602. *
  603. * Returns : None
  604. ************************************************************************************************************************
  605. */
  606. void OSQPost (OS_Q *p_q,
  607. void *p_void,
  608. OS_MSG_SIZE msg_size,
  609. OS_OPT opt,
  610. OS_ERR *p_err)
  611. {
  612. CPU_TS ts;
  613. #ifdef OS_SAFETY_CRITICAL
  614. if (p_err == (OS_ERR *)0) {
  615. OS_SAFETY_CRITICAL_EXCEPTION();
  616. return;
  617. }
  618. #endif
  619. #if OS_CFG_ARG_CHK_EN > 0u
  620. if (p_q == (OS_Q *)0) { /* Validate arguments */
  621. *p_err = OS_ERR_OBJ_PTR_NULL;
  622. return;
  623. }
  624. #endif
  625. #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
  626. if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
  627. *p_err = OS_ERR_OBJ_TYPE;
  628. return;
  629. }
  630. #endif
  631. ts = OS_TS_GET(); /* Get timestamp */
  632. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  633. if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
  634. OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_Q, /* Post to ISR queue */
  635. (void *)p_q,
  636. (void *)p_void,
  637. (OS_MSG_SIZE)msg_size,
  638. (OS_FLAGS )0,
  639. (OS_OPT )opt,
  640. (CPU_TS )ts,
  641. (OS_ERR *)p_err);
  642. return;
  643. }
  644. #endif
  645. OS_QPost(p_q,
  646. p_void,
  647. msg_size,
  648. opt,
  649. ts,
  650. p_err);
  651. }
  652. /*$PAGE*/
  653. /*
  654. ************************************************************************************************************************
  655. * CLEAR THE CONTENTS OF A MESSAGE QUEUE
  656. *
  657. * Description: This function is called by OSQDel() to clear the contents of a message queue
  658. *
  659. * Argument(s): p_q is a pointer to the queue to clear
  660. * ---
  661. *
  662. * Returns : none
  663. *
  664. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  665. ************************************************************************************************************************
  666. */
  667. void OS_QClr (OS_Q *p_q)
  668. {
  669. (void)OS_MsgQFreeAll(&p_q->MsgQ); /* Return all OS_MSGs to the free list */
  670. p_q->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */
  671. p_q->NamePtr = (CPU_CHAR *)((void *)"?Q");
  672. OS_MsgQInit(&p_q->MsgQ, /* Initialize the list of OS_MSGs */
  673. 0u);
  674. OS_PendListInit(&p_q->PendList); /* Initialize the waiting list */
  675. }
  676. /*$PAGE*/
  677. /*
  678. ************************************************************************************************************************
  679. * ADD/REMOVE MESSAGE QUEUE TO/FROM DEBUG LIST
  680. *
  681. * Description: These functions are called by uC/OS-III to add or remove a message queue to/from a message queue debug
  682. * list.
  683. *
  684. * Arguments : p_q is a pointer to the message queue to add/remove
  685. *
  686. * Returns : none
  687. *
  688. * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
  689. ************************************************************************************************************************
  690. */
  691. #if OS_CFG_DBG_EN > 0u
  692. void OS_QDbgListAdd (OS_Q *p_q)
  693. {
  694. p_q->DbgNamePtr = (CPU_CHAR *)((void *)" ");
  695. p_q->DbgPrevPtr = (OS_Q *)0;
  696. if (OSQDbgListPtr == (OS_Q *)0) {
  697. p_q->DbgNextPtr = (OS_Q *)0;
  698. } else {
  699. p_q->DbgNextPtr = OSQDbgListPtr;
  700. OSQDbgListPtr->DbgPrevPtr = p_q;
  701. }
  702. OSQDbgListPtr = p_q;
  703. }
  704. void OS_QDbgListRemove (OS_Q *p_q)
  705. {
  706. OS_Q *p_q_next;
  707. OS_Q *p_q_prev;
  708. p_q_prev = p_q->DbgPrevPtr;
  709. p_q_next = p_q->DbgNextPtr;
  710. if (p_q_prev == (OS_Q *)0) {
  711. OSQDbgListPtr = p_q_next;
  712. if (p_q_next != (OS_Q *)0) {
  713. p_q_next->DbgPrevPtr = (OS_Q *)0;
  714. }
  715. p_q->DbgNextPtr = (OS_Q *)0;
  716. } else if (p_q_next == (OS_Q *)0) {
  717. p_q_prev->DbgNextPtr = (OS_Q *)0;
  718. p_q->DbgPrevPtr = (OS_Q *)0;
  719. } else {
  720. p_q_prev->DbgNextPtr = p_q_next;
  721. p_q_next->DbgPrevPtr = p_q_prev;
  722. p_q->DbgNextPtr = (OS_Q *)0;
  723. p_q->DbgPrevPtr = (OS_Q *)0;
  724. }
  725. }
  726. #endif
  727. /*$PAGE*/
  728. /*
  729. ************************************************************************************************************************
  730. * MESSAGE QUEUE INITIALIZATION
  731. *
  732. * Description: This function is called by OSInit() to initialize the message queue management.
  733. *
  734. * Arguments : p_err is a pointer to a variable that will receive an error code.
  735. *
  736. * OS_ERR_NONE the call was successful
  737. *
  738. * Returns : none
  739. *
  740. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  741. ************************************************************************************************************************
  742. */
  743. void OS_QInit (OS_ERR *p_err)
  744. {
  745. #ifdef OS_SAFETY_CRITICAL
  746. if (p_err == (OS_ERR *)0) {
  747. OS_SAFETY_CRITICAL_EXCEPTION();
  748. return;
  749. }
  750. #endif
  751. #if OS_CFG_DBG_EN > 0u
  752. OSQDbgListPtr = (OS_Q *)0;
  753. #endif
  754. OSQQty = (OS_OBJ_QTY)0;
  755. *p_err = OS_ERR_NONE;
  756. }
  757. /*$PAGE*/
  758. /*
  759. ************************************************************************************************************************
  760. * POST MESSAGE TO A QUEUE
  761. *
  762. * Description: This function sends a message to a queue. With the 'opt' argument, you can specify whether the message
  763. * is broadcast to all waiting tasks and/or whether you post the message to the front of the queue (LIFO)
  764. * or normally (FIFO) at the end of the queue.
  765. *
  766. * Arguments : p_q is a pointer to a message queue that must have been created by OSQCreate().
  767. *
  768. * p_void is a pointer to the message to send.
  769. *
  770. * msg_size specifies the size of the message (in bytes)
  771. *
  772. * opt determines the type of POST performed:
  773. *
  774. * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the queue
  775. *
  776. * OS_OPT_POST_FIFO POST as FIFO and wake up single waiting task
  777. * OS_OPT_POST_LIFO POST as LIFO and wake up single waiting task
  778. *
  779. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  780. *
  781. * ts is the timestamp of the post
  782. *
  783. * p_err is a pointer to a variable that will contain an error code returned by this function.
  784. *
  785. * OS_ERR_NONE The call was successful and the message was sent
  786. * OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs to use to place the message into
  787. * OS_ERR_OBJ_PTR_NULL If 'p_q' is a NULL pointer
  788. * OS_ERR_OBJ_TYPE If the message queue was not initialized
  789. * OS_ERR_Q_MAX If the queue is full
  790. *
  791. * Returns : None
  792. *
  793. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  794. ************************************************************************************************************************
  795. */
  796. void OS_QPost (OS_Q *p_q,
  797. void *p_void,
  798. OS_MSG_SIZE msg_size,
  799. OS_OPT opt,
  800. CPU_TS ts,
  801. OS_ERR *p_err)
  802. {
  803. OS_OBJ_QTY cnt;
  804. OS_OPT post_type;
  805. OS_PEND_LIST *p_pend_list;
  806. OS_PEND_DATA *p_pend_data;
  807. OS_PEND_DATA *p_pend_data_next;
  808. OS_TCB *p_tcb;
  809. CPU_SR_ALLOC();
  810. OS_CRITICAL_ENTER();
  811. p_pend_list = &p_q->PendList;
  812. if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { /* Any task waiting on message queue? */
  813. if ((opt & OS_OPT_POST_LIFO) == (OS_OPT)0) { /* Determine whether we post FIFO or LIFO */
  814. post_type = OS_OPT_POST_FIFO;
  815. } else {
  816. post_type = OS_OPT_POST_LIFO;
  817. }
  818. OS_MsgQPut(&p_q->MsgQ, /* Place message in the message queue */
  819. p_void,
  820. msg_size,
  821. post_type,
  822. ts,
  823. p_err);
  824. OS_CRITICAL_EXIT();
  825. return;
  826. }
  827. if ((opt & OS_OPT_POST_ALL) != (OS_OPT)0) { /* Post message to all tasks waiting? */
  828. cnt = p_pend_list->NbrEntries; /* Yes */
  829. } else {
  830. cnt = (OS_OBJ_QTY)1; /* No */
  831. }
  832. p_pend_data = p_pend_list->HeadPtr;
  833. while (cnt > 0u) {
  834. p_tcb = p_pend_data->TCBPtr;
  835. p_pend_data_next = p_pend_data->NextPtr;
  836. OS_Post((OS_PEND_OBJ *)((void *)p_q),
  837. p_tcb,
  838. p_void,
  839. msg_size,
  840. ts);
  841. p_pend_data = p_pend_data_next;
  842. cnt--;
  843. }
  844. OS_CRITICAL_EXIT_NO_SCHED();
  845. if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
  846. OSSched(); /* Run the scheduler */
  847. }
  848. *p_err = OS_ERR_NONE;
  849. }
  850. #endif