os_q.c 39 KB

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