os_mutex.c 35 KB

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