os_sem.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  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. * SEMAPHORE MANAGEMENT
  19. *
  20. * File : os_sem.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_sem__c = "$Id: $";
  28. #endif
  29. #if (OS_CFG_SEM_EN > 0u)
  30. /*
  31. ************************************************************************************************************************
  32. * CREATE A SEMAPHORE
  33. *
  34. * Description: This function creates a semaphore.
  35. *
  36. * Arguments : p_sem is a pointer to the semaphore to initialize. Your application is responsible for
  37. * allocating storage for the semaphore.
  38. *
  39. * p_name is a pointer to the name you would like to give the semaphore.
  40. *
  41. * cnt is the initial value for the semaphore.
  42. * If used to share resources, you should initialize to the number of resources available.
  43. * If used to signal the occurrence of event(s) then you should initialize to 0.
  44. *
  45. * p_err is a pointer to a variable that will contain an error code returned by this function.
  46. *
  47. * OS_ERR_NONE If the call was successful
  48. * OS_ERR_CREATE_ISR If you called this function from an ISR
  49. * OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the semaphore after you
  50. * called OSSafetyCriticalStart()
  51. * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer
  52. * OS_ERR_OBJ_CREATED If the semaphore was already created
  53. *
  54. * Returns : none
  55. *
  56. * Note(s) : none
  57. ************************************************************************************************************************
  58. */
  59. void OSSemCreate (OS_SEM *p_sem,
  60. CPU_CHAR *p_name,
  61. OS_SEM_CTR cnt,
  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_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
  85. *p_err = OS_ERR_OBJ_PTR_NULL;
  86. return;
  87. }
  88. #endif
  89. CPU_CRITICAL_ENTER();
  90. #if (OS_OBJ_TYPE_REQ > 0u)
  91. #if (OS_CFG_OBJ_CREATED_CHK_EN > 0u)
  92. if (p_sem->Type == OS_OBJ_TYPE_SEM) {
  93. CPU_CRITICAL_EXIT();
  94. *p_err = OS_ERR_OBJ_CREATED;
  95. return;
  96. }
  97. #endif
  98. p_sem->Type = OS_OBJ_TYPE_SEM; /* Mark the data structure as a semaphore */
  99. #endif
  100. p_sem->Ctr = cnt; /* Set semaphore value */
  101. #if (OS_CFG_TS_EN > 0u)
  102. p_sem->TS = 0u;
  103. #endif
  104. #if (OS_CFG_DBG_EN > 0u)
  105. p_sem->NamePtr = p_name; /* Save the name of the semaphore */
  106. #else
  107. (void)p_name;
  108. #endif
  109. OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */
  110. #if (OS_CFG_DBG_EN > 0u)
  111. OS_SemDbgListAdd(p_sem);
  112. OSSemQty++;
  113. #endif
  114. OS_TRACE_SEM_CREATE(p_sem, p_name);
  115. CPU_CRITICAL_EXIT();
  116. *p_err = OS_ERR_NONE;
  117. }
  118. /*
  119. ************************************************************************************************************************
  120. * DELETE A SEMAPHORE
  121. *
  122. * Description: This function deletes a semaphore.
  123. *
  124. * Arguments : p_sem is a pointer to the semaphore to delete
  125. *
  126. * opt determines delete options as follows:
  127. *
  128. * OS_OPT_DEL_NO_PEND Delete semaphore ONLY if no task pending
  129. * OS_OPT_DEL_ALWAYS Deletes the semaphore even if tasks are waiting.
  130. * In this case, all the tasks pending will be readied.
  131. *
  132. * p_err is a pointer to a variable that will contain an error code returned by this function.
  133. *
  134. * OS_ERR_NONE The call was successful and the semaphore was deleted
  135. * OS_ERR_DEL_ISR If you attempted to delete the semaphore from an ISR
  136. * OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the semaphore after you called
  137. * OSStart()
  138. * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer
  139. * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
  140. * OS_ERR_OPT_INVALID An invalid option was specified
  141. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  142. * OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore
  143. *
  144. * Returns : == 0 if no tasks were waiting on the semaphore, or upon error.
  145. * > 0 if one or more tasks waiting on the semaphore are now readied and informed.
  146. *
  147. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the semaphore
  148. * MUST check the return code of OSSemPend().
  149. * 2) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in applications where
  150. * the semaphore is used for mutual exclusion because the resource(s) will no longer be guarded by the
  151. * semaphore.
  152. ************************************************************************************************************************
  153. */
  154. #if (OS_CFG_SEM_DEL_EN > 0u)
  155. OS_OBJ_QTY OSSemDel (OS_SEM *p_sem,
  156. OS_OPT opt,
  157. OS_ERR *p_err)
  158. {
  159. OS_OBJ_QTY nbr_tasks;
  160. OS_PEND_LIST *p_pend_list;
  161. OS_TCB *p_tcb;
  162. CPU_TS ts;
  163. CPU_SR_ALLOC();
  164. #ifdef OS_SAFETY_CRITICAL
  165. if (p_err == (OS_ERR *)0) {
  166. OS_SAFETY_CRITICAL_EXCEPTION();
  167. return (0u);
  168. }
  169. #endif
  170. OS_TRACE_SEM_DEL_ENTER(p_sem, opt);
  171. #ifdef OS_SAFETY_CRITICAL_IEC61508
  172. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  173. OS_TRACE_SEM_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME);
  174. *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
  175. return (0u);
  176. }
  177. #endif
  178. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  179. if (OSIntNestingCtr > 0u) { /* Not allowed to delete a semaphore from an ISR */
  180. OS_TRACE_SEM_DEL_EXIT(OS_ERR_DEL_ISR);
  181. *p_err = OS_ERR_DEL_ISR;
  182. return (0u);
  183. }
  184. #endif
  185. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  186. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  187. OS_TRACE_SEM_DEL_EXIT(OS_ERR_OS_NOT_RUNNING);
  188. *p_err = OS_ERR_OS_NOT_RUNNING;
  189. return (0u);
  190. }
  191. #endif
  192. #if (OS_CFG_ARG_CHK_EN > 0u)
  193. if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
  194. OS_TRACE_SEM_DEL_EXIT(OS_ERR_OBJ_PTR_NULL);
  195. *p_err = OS_ERR_OBJ_PTR_NULL;
  196. return (0u);
  197. }
  198. #endif
  199. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  200. if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
  201. OS_TRACE_SEM_DEL_EXIT(OS_ERR_OBJ_TYPE);
  202. *p_err = OS_ERR_OBJ_TYPE;
  203. return (0u);
  204. }
  205. #endif
  206. CPU_CRITICAL_ENTER();
  207. p_pend_list = &p_sem->PendList;
  208. nbr_tasks = 0u;
  209. switch (opt) {
  210. case OS_OPT_DEL_NO_PEND: /* Delete semaphore only if no task waiting */
  211. if (p_pend_list->HeadPtr == (OS_TCB *)0) {
  212. #if (OS_CFG_DBG_EN > 0u)
  213. OS_SemDbgListRemove(p_sem);
  214. OSSemQty--;
  215. #endif
  216. OS_TRACE_SEM_DEL(p_sem);
  217. OS_SemClr(p_sem);
  218. CPU_CRITICAL_EXIT();
  219. *p_err = OS_ERR_NONE;
  220. } else {
  221. CPU_CRITICAL_EXIT();
  222. *p_err = OS_ERR_TASK_WAITING;
  223. }
  224. break;
  225. case OS_OPT_DEL_ALWAYS: /* Always delete the semaphore */
  226. #if (OS_CFG_TS_EN > 0u)
  227. ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
  228. #else
  229. ts = 0u;
  230. #endif
  231. while (p_pend_list->HeadPtr != (OS_TCB *)0) { /* Remove all tasks on the pend list */
  232. p_tcb = p_pend_list->HeadPtr;
  233. OS_PendAbort(p_tcb,
  234. ts,
  235. OS_STATUS_PEND_DEL);
  236. nbr_tasks++;
  237. }
  238. #if (OS_CFG_DBG_EN > 0u)
  239. OS_SemDbgListRemove(p_sem);
  240. OSSemQty--;
  241. #endif
  242. OS_TRACE_SEM_DEL(p_sem);
  243. OS_SemClr(p_sem);
  244. CPU_CRITICAL_EXIT();
  245. OSSched(); /* Find highest priority task ready to run */
  246. *p_err = OS_ERR_NONE;
  247. break;
  248. default:
  249. CPU_CRITICAL_EXIT();
  250. *p_err = OS_ERR_OPT_INVALID;
  251. break;
  252. }
  253. OS_TRACE_SEM_DEL_EXIT(*p_err);
  254. return (nbr_tasks);
  255. }
  256. #endif
  257. /*
  258. ************************************************************************************************************************
  259. * PEND ON SEMAPHORE
  260. *
  261. * Description: This function waits for a semaphore.
  262. *
  263. * Arguments : p_sem is a pointer to the semaphore
  264. *
  265. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for the
  266. * resource up to the amount of time (in 'ticks') specified by this argument. If you specify
  267. * 0, however, your task will wait forever at the specified semaphore or, until the resource
  268. * becomes available (or the event occurs).
  269. *
  270. * opt determines whether the user wants to block if the semaphore is available or not:
  271. *
  272. * OS_OPT_PEND_BLOCKING
  273. * OS_OPT_PEND_NON_BLOCKING
  274. *
  275. * p_ts is a pointer to a variable that will receive the timestamp of when the semaphore was posted
  276. * or pend aborted or the semaphore deleted. If you pass a NULL pointer (i.e. (CPU_TS*)0)
  277. * then you will not get the timestamp. In other words, passing a NULL pointer is valid
  278. * and indicates that you don't need the timestamp.
  279. *
  280. * p_err is a pointer to a variable that will contain an error code returned by this function.
  281. *
  282. * OS_ERR_NONE The call was successful and your task owns the resource
  283. * or, the event you are waiting for occurred
  284. * OS_ERR_OBJ_DEL If 'p_sem' was deleted
  285. * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer
  286. * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
  287. * OS_ERR_OPT_INVALID If you specified an invalid value for 'opt'
  288. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  289. * OS_ERR_PEND_ABORT If the pend was aborted by another task
  290. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  291. * would lead to a suspension
  292. * OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the semaphore was not
  293. * available
  294. * OS_ERR_SCHED_LOCKED If you called this function when the scheduler is locked
  295. * OS_ERR_STATUS_INVALID Pend status is invalid
  296. * OS_ERR_TIMEOUT The semaphore was not received within the specified
  297. * timeout
  298. * OS_ERR_TICK_DISABLED If kernel ticks are disabled and a timeout is specified
  299. *
  300. *
  301. * Returns : The current value of the semaphore counter or 0 if not available.
  302. *
  303. * Note(s) : This API 'MUST NOT' be called from a timer callback function.
  304. ************************************************************************************************************************
  305. */
  306. OS_SEM_CTR OSSemPend (OS_SEM *p_sem,
  307. OS_TICK timeout,
  308. OS_OPT opt,
  309. CPU_TS *p_ts,
  310. OS_ERR *p_err)
  311. {
  312. OS_SEM_CTR ctr;
  313. CPU_SR_ALLOC();
  314. #if (OS_CFG_TS_EN == 0u)
  315. (void)p_ts; /* Prevent compiler warning for not using 'ts' */
  316. #endif
  317. #ifdef OS_SAFETY_CRITICAL
  318. if (p_err == (OS_ERR *)0) {
  319. OS_SAFETY_CRITICAL_EXCEPTION();
  320. return (0u);
  321. }
  322. #endif
  323. OS_TRACE_SEM_PEND_ENTER(p_sem, timeout, opt, p_ts);
  324. #if (OS_CFG_TICK_EN == 0u)
  325. if (timeout != 0u) {
  326. *p_err = OS_ERR_TICK_DISABLED;
  327. OS_TRACE_SEM_PEND_FAILED(p_sem);
  328. OS_TRACE_SEM_PEND_EXIT(OS_ERR_TICK_DISABLED);
  329. return (0u);
  330. }
  331. #endif
  332. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  333. if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
  334. if ((opt & OS_OPT_PEND_NON_BLOCKING) != OS_OPT_PEND_NON_BLOCKING) {
  335. OS_TRACE_SEM_PEND_FAILED(p_sem);
  336. OS_TRACE_SEM_PEND_EXIT(OS_ERR_PEND_ISR);
  337. *p_err = OS_ERR_PEND_ISR;
  338. return (0u);
  339. }
  340. }
  341. #endif
  342. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  343. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  344. OS_TRACE_SEM_PEND_EXIT(OS_ERR_OS_NOT_RUNNING);
  345. *p_err = OS_ERR_OS_NOT_RUNNING;
  346. return (0u);
  347. }
  348. #endif
  349. #if (OS_CFG_ARG_CHK_EN > 0u)
  350. if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
  351. OS_TRACE_SEM_PEND_EXIT(OS_ERR_OBJ_PTR_NULL);
  352. *p_err = OS_ERR_OBJ_PTR_NULL;
  353. return (0u);
  354. }
  355. switch (opt) { /* Validate 'opt' */
  356. case OS_OPT_PEND_BLOCKING:
  357. case OS_OPT_PEND_NON_BLOCKING:
  358. break;
  359. default:
  360. OS_TRACE_SEM_PEND_FAILED(p_sem);
  361. OS_TRACE_SEM_PEND_EXIT(OS_ERR_OPT_INVALID);
  362. *p_err = OS_ERR_OPT_INVALID;
  363. return (0u);
  364. }
  365. #endif
  366. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  367. if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
  368. OS_TRACE_SEM_PEND_FAILED(p_sem);
  369. OS_TRACE_SEM_PEND_EXIT(OS_ERR_OBJ_TYPE);
  370. *p_err = OS_ERR_OBJ_TYPE;
  371. return (0u);
  372. }
  373. #endif
  374. CPU_CRITICAL_ENTER();
  375. if (p_sem->Ctr > 0u) { /* Resource available? */
  376. p_sem->Ctr--; /* Yes, caller may proceed */
  377. #if (OS_CFG_TS_EN > 0u)
  378. if (p_ts != (CPU_TS *)0) {
  379. *p_ts = p_sem->TS; /* get timestamp of last post */
  380. }
  381. #endif
  382. ctr = p_sem->Ctr;
  383. OS_TRACE_SEM_PEND(p_sem);
  384. CPU_CRITICAL_EXIT();
  385. OS_TRACE_SEM_PEND_EXIT(OS_ERR_NONE);
  386. *p_err = OS_ERR_NONE;
  387. return (ctr);
  388. }
  389. if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { /* Caller wants to block if not available? */
  390. #if (OS_CFG_TS_EN > 0u)
  391. if (p_ts != (CPU_TS *)0) {
  392. *p_ts = 0u;
  393. }
  394. #endif
  395. ctr = p_sem->Ctr; /* No */
  396. CPU_CRITICAL_EXIT();
  397. OS_TRACE_SEM_PEND_FAILED(p_sem);
  398. OS_TRACE_SEM_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
  399. *p_err = OS_ERR_PEND_WOULD_BLOCK;
  400. return (ctr);
  401. } else { /* Yes */
  402. if (OSSchedLockNestingCtr > 0u) { /* Can't pend when the scheduler is locked */
  403. #if (OS_CFG_TS_EN > 0u)
  404. if (p_ts != (CPU_TS *)0) {
  405. *p_ts = 0u;
  406. }
  407. #endif
  408. CPU_CRITICAL_EXIT();
  409. OS_TRACE_SEM_PEND_FAILED(p_sem);
  410. OS_TRACE_SEM_PEND_EXIT(OS_ERR_SCHED_LOCKED);
  411. *p_err = OS_ERR_SCHED_LOCKED;
  412. return (0u);
  413. }
  414. }
  415. OS_Pend((OS_PEND_OBJ *)((void *)p_sem), /* Block task pending on Semaphore */
  416. OSTCBCurPtr,
  417. OS_TASK_PEND_ON_SEM,
  418. timeout);
  419. CPU_CRITICAL_EXIT();
  420. OS_TRACE_SEM_PEND_BLOCK(p_sem);
  421. OSSched(); /* Find the next highest priority task ready to run */
  422. CPU_CRITICAL_ENTER();
  423. switch (OSTCBCurPtr->PendStatus) {
  424. case OS_STATUS_PEND_OK: /* We got the semaphore */
  425. #if (OS_CFG_TS_EN > 0u)
  426. if (p_ts != (CPU_TS *)0) {
  427. *p_ts = OSTCBCurPtr->TS;
  428. }
  429. #endif
  430. OS_TRACE_SEM_PEND(p_sem);
  431. *p_err = OS_ERR_NONE;
  432. break;
  433. case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */
  434. #if (OS_CFG_TS_EN > 0u)
  435. if (p_ts != (CPU_TS *)0) {
  436. *p_ts = OSTCBCurPtr->TS;
  437. }
  438. #endif
  439. OS_TRACE_SEM_PEND_FAILED(p_sem);
  440. *p_err = OS_ERR_PEND_ABORT;
  441. break;
  442. case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */
  443. #if (OS_CFG_TS_EN > 0u)
  444. if (p_ts != (CPU_TS *)0) {
  445. *p_ts = 0u;
  446. }
  447. #endif
  448. OS_TRACE_SEM_PEND_FAILED(p_sem);
  449. *p_err = OS_ERR_TIMEOUT;
  450. break;
  451. case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */
  452. #if (OS_CFG_TS_EN > 0u)
  453. if (p_ts != (CPU_TS *)0) {
  454. *p_ts = OSTCBCurPtr->TS;
  455. }
  456. #endif
  457. OS_TRACE_SEM_PEND_FAILED(p_sem);
  458. *p_err = OS_ERR_OBJ_DEL;
  459. break;
  460. default:
  461. OS_TRACE_SEM_PEND_FAILED(p_sem);
  462. *p_err = OS_ERR_STATUS_INVALID;
  463. CPU_CRITICAL_EXIT();
  464. OS_TRACE_SEM_PEND_EXIT(*p_err);
  465. return (0u);
  466. }
  467. ctr = p_sem->Ctr;
  468. CPU_CRITICAL_EXIT();
  469. OS_TRACE_SEM_PEND_EXIT(*p_err);
  470. return (ctr);
  471. }
  472. /*
  473. ************************************************************************************************************************
  474. * ABORT WAITING ON A SEMAPHORE
  475. *
  476. * Description: This function aborts & readies any tasks currently waiting on a semaphore. This function should be used
  477. * to fault-abort the wait on the semaphore, rather than to normally signal the semaphore via OSSemPost().
  478. *
  479. * Arguments : p_sem is a pointer to the semaphore
  480. *
  481. * opt determines the type of ABORT performed:
  482. *
  483. * OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the semaphore
  484. * OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the semaphore
  485. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  486. *
  487. * p_err is a pointer to a variable that will contain an error code returned by this function.
  488. *
  489. * OS_ERR_NONE At least one task waiting on the semaphore was readied and
  490. * informed of the aborted wait; check return value for the
  491. * number of tasks whose wait on the semaphore was aborted.
  492. * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
  493. * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
  494. * OS_ERR_OPT_INVALID If you specified an invalid option
  495. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  496. * OS_ERR_PEND_ABORT_ISR If you called this function from an ISR
  497. * OS_ERR_PEND_ABORT_NONE No task were pending
  498. *
  499. * Returns : == 0 if no tasks were waiting on the semaphore, or upon error.
  500. * > 0 if one or more tasks waiting on the semaphore are now readied and informed.
  501. *
  502. * Note(s) : none
  503. ************************************************************************************************************************
  504. */
  505. #if (OS_CFG_SEM_PEND_ABORT_EN > 0u)
  506. OS_OBJ_QTY OSSemPendAbort (OS_SEM *p_sem,
  507. OS_OPT opt,
  508. OS_ERR *p_err)
  509. {
  510. OS_PEND_LIST *p_pend_list;
  511. OS_TCB *p_tcb;
  512. CPU_TS ts;
  513. OS_OBJ_QTY nbr_tasks;
  514. CPU_SR_ALLOC();
  515. #ifdef OS_SAFETY_CRITICAL
  516. if (p_err == (OS_ERR *)0) {
  517. OS_SAFETY_CRITICAL_EXCEPTION();
  518. return (0u);
  519. }
  520. #endif
  521. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  522. if (OSIntNestingCtr > 0u) { /* Not allowed to Pend Abort from an ISR */
  523. *p_err = OS_ERR_PEND_ABORT_ISR;
  524. return (0u);
  525. }
  526. #endif
  527. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  528. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  529. *p_err = OS_ERR_OS_NOT_RUNNING;
  530. return (0u);
  531. }
  532. #endif
  533. #if (OS_CFG_ARG_CHK_EN > 0u)
  534. if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
  535. *p_err = OS_ERR_OBJ_PTR_NULL;
  536. return (0u);
  537. }
  538. switch (opt) { /* Validate 'opt' */
  539. case OS_OPT_PEND_ABORT_1:
  540. case OS_OPT_PEND_ABORT_ALL:
  541. case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED:
  542. case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
  543. break;
  544. default:
  545. *p_err = OS_ERR_OPT_INVALID;
  546. return (0u);
  547. }
  548. #endif
  549. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  550. if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
  551. *p_err = OS_ERR_OBJ_TYPE;
  552. return (0u);
  553. }
  554. #endif
  555. CPU_CRITICAL_ENTER();
  556. p_pend_list = &p_sem->PendList;
  557. if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on semaphore? */
  558. CPU_CRITICAL_EXIT(); /* No */
  559. *p_err = OS_ERR_PEND_ABORT_NONE;
  560. return (0u);
  561. }
  562. nbr_tasks = 0u;
  563. #if (OS_CFG_TS_EN > 0u)
  564. ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
  565. #else
  566. ts = 0u;
  567. #endif
  568. while (p_pend_list->HeadPtr != (OS_TCB *)0) {
  569. p_tcb = p_pend_list->HeadPtr;
  570. OS_PendAbort(p_tcb,
  571. ts,
  572. OS_STATUS_PEND_ABORT);
  573. nbr_tasks++;
  574. if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */
  575. break; /* No */
  576. }
  577. }
  578. CPU_CRITICAL_EXIT();
  579. if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
  580. OSSched(); /* Run the scheduler */
  581. }
  582. *p_err = OS_ERR_NONE;
  583. return (nbr_tasks);
  584. }
  585. #endif
  586. /*
  587. ************************************************************************************************************************
  588. * POST TO A SEMAPHORE
  589. *
  590. * Description: This function signals a semaphore.
  591. *
  592. * Arguments : p_sem is a pointer to the semaphore
  593. *
  594. * opt determines the type of POST performed:
  595. *
  596. * OS_OPT_POST_1 POST and ready only the highest priority task waiting on semaphore
  597. * (if tasks are waiting).
  598. * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the semaphore
  599. *
  600. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  601. *
  602. *
  603. * p_err is a pointer to a variable that will contain an error code returned by this function.
  604. *
  605. * OS_ERR_NONE The call was successful and the semaphore was signaled
  606. * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer
  607. * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
  608. * OS_ERR_OPT_INVALID If you specified an invalid option
  609. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  610. * OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow
  611. *
  612. * Returns : The current value of the semaphore counter or 0 upon error.
  613. *
  614. * Note(s) : 1) OS_OPT_POST_NO_SCHED can be added with one of the other options.
  615. ************************************************************************************************************************
  616. */
  617. OS_SEM_CTR OSSemPost (OS_SEM *p_sem,
  618. OS_OPT opt,
  619. OS_ERR *p_err)
  620. {
  621. OS_SEM_CTR ctr;
  622. OS_PEND_LIST *p_pend_list;
  623. OS_TCB *p_tcb;
  624. OS_TCB *p_tcb_next;
  625. CPU_TS ts;
  626. CPU_SR_ALLOC();
  627. #ifdef OS_SAFETY_CRITICAL
  628. if (p_err == (OS_ERR *)0) {
  629. OS_SAFETY_CRITICAL_EXCEPTION();
  630. return (0u);
  631. }
  632. #endif
  633. OS_TRACE_SEM_POST_ENTER(p_sem, opt);
  634. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  635. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  636. OS_TRACE_SEM_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
  637. *p_err = OS_ERR_OS_NOT_RUNNING;
  638. return (0u);
  639. }
  640. #endif
  641. #if (OS_CFG_ARG_CHK_EN > 0u)
  642. if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
  643. OS_TRACE_SEM_POST_FAILED(p_sem);
  644. OS_TRACE_SEM_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
  645. *p_err = OS_ERR_OBJ_PTR_NULL;
  646. return (0u);
  647. }
  648. switch (opt) { /* Validate 'opt' */
  649. case OS_OPT_POST_1:
  650. case OS_OPT_POST_ALL:
  651. case OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED:
  652. case OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED:
  653. break;
  654. default:
  655. OS_TRACE_SEM_POST_FAILED(p_sem);
  656. OS_TRACE_SEM_POST_EXIT(OS_ERR_OPT_INVALID);
  657. *p_err = OS_ERR_OPT_INVALID;
  658. return (0u);
  659. }
  660. #endif
  661. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  662. if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
  663. OS_TRACE_SEM_POST_FAILED(p_sem);
  664. OS_TRACE_SEM_POST_EXIT(OS_ERR_OBJ_TYPE);
  665. *p_err = OS_ERR_OBJ_TYPE;
  666. return (0u);
  667. }
  668. #endif
  669. #if (OS_CFG_TS_EN > 0u)
  670. ts = OS_TS_GET(); /* Get timestamp */
  671. #else
  672. ts = 0u;
  673. #endif
  674. OS_TRACE_SEM_POST(p_sem);
  675. CPU_CRITICAL_ENTER();
  676. p_pend_list = &p_sem->PendList;
  677. if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on semaphore? */
  678. if (p_sem->Ctr == (OS_SEM_CTR)-1) {
  679. CPU_CRITICAL_EXIT();
  680. *p_err = OS_ERR_SEM_OVF;
  681. OS_TRACE_SEM_POST_EXIT(*p_err);
  682. return (0u);
  683. }
  684. p_sem->Ctr++; /* No */
  685. ctr = p_sem->Ctr;
  686. #if (OS_CFG_TS_EN > 0u)
  687. p_sem->TS = ts; /* Save timestamp in semaphore control block */
  688. #endif
  689. CPU_CRITICAL_EXIT();
  690. *p_err = OS_ERR_NONE;
  691. OS_TRACE_SEM_POST_EXIT(*p_err);
  692. return (ctr);
  693. }
  694. p_tcb = p_pend_list->HeadPtr;
  695. while (p_tcb != (OS_TCB *)0) {
  696. p_tcb_next = p_tcb->PendNextPtr;
  697. OS_Post((OS_PEND_OBJ *)((void *)p_sem),
  698. p_tcb,
  699. (void *)0,
  700. 0u,
  701. ts);
  702. if ((opt & OS_OPT_POST_ALL) == 0u) { /* Post to all tasks waiting? */
  703. break; /* No */
  704. }
  705. p_tcb = p_tcb_next;
  706. }
  707. CPU_CRITICAL_EXIT();
  708. if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
  709. OSSched(); /* Run the scheduler */
  710. }
  711. *p_err = OS_ERR_NONE;
  712. OS_TRACE_SEM_POST_EXIT(*p_err);
  713. return (0u);
  714. }
  715. /*
  716. ************************************************************************************************************************
  717. * SET SEMAPHORE
  718. *
  719. * Description: This function sets the semaphore count to the value specified as an argument. Typically, this value
  720. * would be 0 but of course, we can set the semaphore to any value.
  721. *
  722. * You would typically use this function when a semaphore is used as a signaling mechanism
  723. * and, you want to reset the count value.
  724. *
  725. * Arguments : p_sem is a pointer to the semaphore
  726. *
  727. * cnt is the new value for the semaphore count. You would pass 0 to reset the semaphore count.
  728. *
  729. * p_err is a pointer to a variable that will contain an error code returned by this function.
  730. *
  731. * OS_ERR_NONE The call was successful and the semaphore value was set
  732. * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer
  733. * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing to a semaphore
  734. * OS_ERR_SET_ISR If called from an ISR
  735. * OS_ERR_TASK_WAITING If tasks are waiting on the semaphore
  736. *
  737. * Returns : None
  738. *
  739. * Note(s) : none
  740. ************************************************************************************************************************
  741. */
  742. #if (OS_CFG_SEM_SET_EN > 0u)
  743. void OSSemSet (OS_SEM *p_sem,
  744. OS_SEM_CTR cnt,
  745. OS_ERR *p_err)
  746. {
  747. OS_PEND_LIST *p_pend_list;
  748. CPU_SR_ALLOC();
  749. #ifdef OS_SAFETY_CRITICAL
  750. if (p_err == (OS_ERR *)0) {
  751. OS_SAFETY_CRITICAL_EXCEPTION();
  752. return;
  753. }
  754. #endif
  755. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  756. if (OSIntNestingCtr > 0u) { /* Can't call this function from an ISR */
  757. *p_err = OS_ERR_SET_ISR;
  758. return;
  759. }
  760. #endif
  761. #if (OS_CFG_ARG_CHK_EN > 0u)
  762. if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
  763. *p_err = OS_ERR_OBJ_PTR_NULL;
  764. return;
  765. }
  766. #endif
  767. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  768. if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
  769. *p_err = OS_ERR_OBJ_TYPE;
  770. return;
  771. }
  772. #endif
  773. *p_err = OS_ERR_NONE;
  774. CPU_CRITICAL_ENTER();
  775. if (p_sem->Ctr > 0u) { /* See if semaphore already has a count */
  776. p_sem->Ctr = cnt; /* Yes, set it to the new value specified. */
  777. } else {
  778. p_pend_list = &p_sem->PendList; /* No */
  779. if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* See if task(s) waiting? */
  780. p_sem->Ctr = cnt; /* No, OK to set the value */
  781. } else {
  782. *p_err = OS_ERR_TASK_WAITING;
  783. }
  784. }
  785. CPU_CRITICAL_EXIT();
  786. }
  787. #endif
  788. /*
  789. ************************************************************************************************************************
  790. * CLEAR THE CONTENTS OF A SEMAPHORE
  791. *
  792. * Description: This function is called by OSSemDel() to clear the contents of a semaphore
  793. *
  794. * Argument(s): p_sem is a pointer to the semaphore to clear
  795. * -----
  796. *
  797. * Returns : none
  798. *
  799. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  800. ************************************************************************************************************************
  801. */
  802. void OS_SemClr (OS_SEM *p_sem)
  803. {
  804. #if (OS_OBJ_TYPE_REQ > 0u)
  805. p_sem->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */
  806. #endif
  807. p_sem->Ctr = 0u; /* Set semaphore value */
  808. #if (OS_CFG_TS_EN > 0u)
  809. p_sem->TS = 0u; /* Clear the time stamp */
  810. #endif
  811. #if (OS_CFG_DBG_EN > 0u)
  812. p_sem->NamePtr = (CPU_CHAR *)((void *)"?SEM");
  813. #endif
  814. OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */
  815. }
  816. /*
  817. ************************************************************************************************************************
  818. * ADD/REMOVE SEMAPHORE TO/FROM DEBUG LIST
  819. *
  820. * Description: These functions are called by uC/OS-III to add or remove a semaphore to/from the debug list.
  821. *
  822. * Arguments : p_sem is a pointer to the semaphore to add/remove
  823. *
  824. * Returns : none
  825. *
  826. * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
  827. ************************************************************************************************************************
  828. */
  829. #if (OS_CFG_DBG_EN > 0u)
  830. void OS_SemDbgListAdd (OS_SEM *p_sem)
  831. {
  832. p_sem->DbgNamePtr = (CPU_CHAR *)((void *)" ");
  833. p_sem->DbgPrevPtr = (OS_SEM *)0;
  834. if (OSSemDbgListPtr == (OS_SEM *)0) {
  835. p_sem->DbgNextPtr = (OS_SEM *)0;
  836. } else {
  837. p_sem->DbgNextPtr = OSSemDbgListPtr;
  838. OSSemDbgListPtr->DbgPrevPtr = p_sem;
  839. }
  840. OSSemDbgListPtr = p_sem;
  841. }
  842. void OS_SemDbgListRemove (OS_SEM *p_sem)
  843. {
  844. OS_SEM *p_sem_next;
  845. OS_SEM *p_sem_prev;
  846. p_sem_prev = p_sem->DbgPrevPtr;
  847. p_sem_next = p_sem->DbgNextPtr;
  848. if (p_sem_prev == (OS_SEM *)0) {
  849. OSSemDbgListPtr = p_sem_next;
  850. if (p_sem_next != (OS_SEM *)0) {
  851. p_sem_next->DbgPrevPtr = (OS_SEM *)0;
  852. }
  853. p_sem->DbgNextPtr = (OS_SEM *)0;
  854. } else if (p_sem_next == (OS_SEM *)0) {
  855. p_sem_prev->DbgNextPtr = (OS_SEM *)0;
  856. p_sem->DbgPrevPtr = (OS_SEM *)0;
  857. } else {
  858. p_sem_prev->DbgNextPtr = p_sem_next;
  859. p_sem_next->DbgPrevPtr = p_sem_prev;
  860. p_sem->DbgNextPtr = (OS_SEM *)0;
  861. p_sem->DbgPrevPtr = (OS_SEM *)0;
  862. }
  863. }
  864. #endif
  865. #endif