os_sem.c 38 KB

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