Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

819 строки
39 KiB

  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. *
  6. * Copyright 1992-2021 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. *
  19. * MUTUAL EXCLUSION SEMAPHORE MANAGEMENT
  20. *
  21. * Filename : os_mutex.c
  22. * Version : V2.93.01
  23. *********************************************************************************************************
  24. */
  25. #ifndef OS_MUTEX_C
  26. #define OS_MUTEX_C
  27. #define MICRIUM_SOURCE
  28. #ifndef OS_MASTER_FILE
  29. #include <ucos_ii.h>
  30. #endif
  31. #if OS_MUTEX_EN > 0u
  32. /*
  33. *********************************************************************************************************
  34. * LOCAL CONSTANTS
  35. *********************************************************************************************************
  36. */
  37. #define OS_MUTEX_KEEP_LOWER_8 ((INT16U)0x00FFu)
  38. #define OS_MUTEX_KEEP_UPPER_8 ((INT16U)0xFF00u)
  39. #define OS_MUTEX_AVAILABLE ((INT16U)0x00FFu)
  40. /*
  41. *********************************************************************************************************
  42. * LOCAL CONSTANTS
  43. *********************************************************************************************************
  44. */
  45. static void OSMutex_RdyAtPrio(OS_TCB *ptcb, INT8U prio);
  46. /*
  47. *********************************************************************************************************
  48. * ACCEPT MUTUAL EXCLUSION SEMAPHORE
  49. *
  50. * Description: This function checks the mutual exclusion semaphore to see if a resource is available.
  51. * Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is
  52. * not available or the event did not occur.
  53. *
  54. * Arguments : pevent is a pointer to the event control block
  55. *
  56. * perr is a pointer to an error code which will be returned to your application:
  57. * OS_ERR_NONE if the call was successful.
  58. * OS_ERR_EVENT_TYPE if 'pevent' is not a pointer to a mutex
  59. * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  60. * OS_ERR_PEND_ISR if you called this function from an ISR
  61. * OS_ERR_PCP_LOWER If the priority of the task that owns the Mutex is
  62. * HIGHER (i.e. a lower number) than the PCP. This error
  63. * indicates that you did not set the PCP higher (lower
  64. * number) than ALL the tasks that compete for the Mutex.
  65. * Unfortunately, this is something that could not be
  66. * detected when the Mutex is created because we don't know
  67. * what tasks will be using the Mutex.
  68. *
  69. * Returns : == OS_TRUE if the resource is available, the mutual exclusion semaphore is acquired
  70. * == OS_FALSE a) if the resource is not available
  71. * b) you didn't pass a pointer to a mutual exclusion semaphore
  72. * c) you called this function from an ISR
  73. *
  74. * Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are
  75. * intended to be used by tasks only.
  76. *********************************************************************************************************
  77. */
  78. #if OS_MUTEX_ACCEPT_EN > 0u
  79. BOOLEAN OSMutexAccept (OS_EVENT *pevent,
  80. INT8U *perr)
  81. {
  82. INT8U pcp; /* Priority Ceiling Priority (PCP) */
  83. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  84. OS_CPU_SR cpu_sr = 0u;
  85. #endif
  86. #ifdef OS_SAFETY_CRITICAL
  87. if (perr == (INT8U *)0) {
  88. OS_SAFETY_CRITICAL_EXCEPTION();
  89. return (OS_FALSE);
  90. }
  91. #endif
  92. #if OS_ARG_CHK_EN > 0u
  93. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  94. *perr = OS_ERR_PEVENT_NULL;
  95. return (OS_FALSE);
  96. }
  97. #endif
  98. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  99. *perr = OS_ERR_EVENT_TYPE;
  100. return (OS_FALSE);
  101. }
  102. if (OSIntNesting > 0u) { /* Make sure it's not called from an ISR */
  103. *perr = OS_ERR_PEND_ISR;
  104. return (OS_FALSE);
  105. }
  106. OS_ENTER_CRITICAL(); /* Get value (0 or 1) of Mutex */
  107. pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */
  108. if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
  109. pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Mask off LSByte (Acquire Mutex) */
  110. pevent->OSEventCnt |= (INT16U)OSTCBCur->OSTCBPrio; /* Save current task priority in LSByte */
  111. pevent->OSEventPtr = (void *)OSTCBCur; /* Link TCB of task owning Mutex */
  112. if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
  113. (OSTCBCur->OSTCBPrio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
  114. OS_EXIT_CRITICAL(); /* ... than current task! */
  115. *perr = OS_ERR_PCP_LOWER;
  116. } else {
  117. OS_EXIT_CRITICAL();
  118. *perr = OS_ERR_NONE;
  119. }
  120. return (OS_TRUE);
  121. }
  122. OS_EXIT_CRITICAL();
  123. *perr = OS_ERR_NONE;
  124. return (OS_FALSE);
  125. }
  126. #endif
  127. /*
  128. *********************************************************************************************************
  129. * CREATE A MUTUAL EXCLUSION SEMAPHORE
  130. *
  131. * Description: This function creates a mutual exclusion semaphore.
  132. *
  133. * Arguments : prio is the priority to use when accessing the mutual exclusion semaphore. In
  134. * other words, when the semaphore is acquired and a higher priority task
  135. * attempts to obtain the semaphore then the priority of the task owning the
  136. * semaphore is raised to this priority. It is assumed that you will specify
  137. * a priority that is LOWER in value than ANY of the tasks competing for the
  138. * mutex. If the priority is specified as OS_PRIO_MUTEX_CEIL_DIS, then the
  139. * priority ceiling promotion is disabled. This way, the tasks accessing the
  140. * semaphore do not have their priority promoted.
  141. *
  142. * perr is a pointer to an error code which will be returned to your application:
  143. * OS_ERR_NONE if the call was successful.
  144. * OS_ERR_CREATE_ISR if you attempted to create a MUTEX from an
  145. * ISR
  146. * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you tried to create a mutex after
  147. * safety critical operation started.
  148. * OS_ERR_PRIO_EXIST if a task at the priority ceiling priority
  149. * already exist.
  150. * OS_ERR_PEVENT_NULL No more event control blocks available.
  151. * OS_ERR_PRIO_INVALID if the priority you specify is higher that
  152. * the maximum allowed (i.e. > OS_LOWEST_PRIO)
  153. *
  154. * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
  155. * created mutex.
  156. * == (void *)0 if an error is detected.
  157. *
  158. * Note(s) : 1) The LEAST significant 8 bits of '.OSEventCnt' hold the priority number of the task
  159. * owning the mutex or 0xFF if no task owns the mutex.
  160. *
  161. * 2) The MOST significant 8 bits of '.OSEventCnt' hold the priority number used to
  162. * reduce priority inversion or 0xFF (OS_PRIO_MUTEX_CEIL_DIS) if priority ceiling
  163. * promotion is disabled.
  164. *********************************************************************************************************
  165. */
  166. OS_EVENT *OSMutexCreate (INT8U prio,
  167. INT8U *perr)
  168. {
  169. OS_EVENT *pevent;
  170. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  171. OS_CPU_SR cpu_sr = 0u;
  172. #endif
  173. #ifdef OS_SAFETY_CRITICAL
  174. if (perr == (INT8U *)0) {
  175. OS_SAFETY_CRITICAL_EXCEPTION();
  176. return ((OS_EVENT *)0);
  177. }
  178. #endif
  179. #ifdef OS_SAFETY_CRITICAL_IEC61508
  180. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  181. OS_SAFETY_CRITICAL_EXCEPTION();
  182. *perr = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  183. return ((OS_EVENT *)0);
  184. }
  185. #endif
  186. #if OS_ARG_CHK_EN > 0u
  187. if (prio != OS_PRIO_MUTEX_CEIL_DIS) {
  188. if (prio >= OS_LOWEST_PRIO) { /* Validate PCP */
  189. *perr = OS_ERR_PRIO_INVALID;
  190. return ((OS_EVENT *)0);
  191. }
  192. }
  193. #endif
  194. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  195. *perr = OS_ERR_CREATE_ISR; /* ... can't CREATE mutex from an ISR */
  196. return ((OS_EVENT *)0);
  197. }
  198. OS_ENTER_CRITICAL();
  199. if (prio != OS_PRIO_MUTEX_CEIL_DIS) {
  200. if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* Mutex priority must not already exist */
  201. OS_EXIT_CRITICAL(); /* Task already exist at priority ... */
  202. *perr = OS_ERR_PRIO_EXIST; /* ... ceiling priority */
  203. return ((OS_EVENT *)0);
  204. }
  205. OSTCBPrioTbl[prio] = OS_TCB_RESERVED; /* Reserve the table entry */
  206. }
  207. pevent = OSEventFreeList; /* Get next free event control block */
  208. if (pevent == (OS_EVENT *)0) { /* See if an ECB was available */
  209. if (prio != OS_PRIO_MUTEX_CEIL_DIS) {
  210. OSTCBPrioTbl[prio] = (OS_TCB *)0; /* No, Release the table entry */
  211. }
  212. OS_EXIT_CRITICAL();
  213. *perr = OS_ERR_PEVENT_NULL; /* No more event control blocks */
  214. return (pevent);
  215. }
  216. OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* Adjust the free list */
  217. OS_EXIT_CRITICAL();
  218. pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
  219. pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE; /* Resource is avail. */
  220. pevent->OSEventPtr = (void *)0; /* No task owning the mutex */
  221. #if OS_EVENT_NAME_EN > 0u
  222. pevent->OSEventName = (INT8U *)(void *)"?";
  223. #endif
  224. OS_EventWaitListInit(pevent);
  225. OS_TRACE_MUTEX_CREATE(pevent, pevent->OSEventName);
  226. *perr = OS_ERR_NONE;
  227. return (pevent);
  228. }
  229. /*
  230. *********************************************************************************************************
  231. * DELETE A MUTEX
  232. *
  233. * Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it.
  234. *
  235. * Arguments : pevent is a pointer to the event control block associated with the desired mutex.
  236. *
  237. * opt determines delete options as follows:
  238. * opt == OS_DEL_NO_PEND Delete mutex ONLY if no task pending
  239. * opt == OS_DEL_ALWAYS Deletes the mutex even if tasks are waiting.
  240. * In this case, all the tasks pending will be readied.
  241. *
  242. * perr is a pointer to an error code that can contain one of the following values:
  243. * OS_ERR_NONE The call was successful and the mutex was deleted
  244. * OS_ERR_DEL_ISR If you attempted to delete the MUTEX from an ISR
  245. * OS_ERR_INVALID_OPT An invalid option was specified
  246. * OS_ERR_ILLEGAL_DEL_RUN_TIME If you tried to delete a mutex after safety
  247. * critical operation started.
  248. * OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex
  249. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
  250. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  251. *
  252. * Returns : pevent upon error
  253. * (OS_EVENT *)0 if the mutex was successfully deleted.
  254. *
  255. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  256. * the mutex MUST check the return code of OSMutexPend().
  257. *
  258. * 2) This call can potentially disable interrupts for a long time. The interrupt disable
  259. * time is directly proportional to the number of tasks waiting on the mutex.
  260. *
  261. * 3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the
  262. * resource(s) will no longer be guarded by the mutex.
  263. *
  264. * 4) IMPORTANT: In the 'OS_DEL_ALWAYS' case, we assume that the owner of the Mutex (if there
  265. * is one) is ready-to-run and is thus NOT pending on another kernel object or
  266. * has delayed itself. In other words, if a task owns the mutex being deleted,
  267. * that task will be made ready-to-run at its original priority.
  268. *********************************************************************************************************
  269. */
  270. #if OS_MUTEX_DEL_EN > 0u
  271. OS_EVENT *OSMutexDel (OS_EVENT *pevent,
  272. INT8U opt,
  273. INT8U *perr)
  274. {
  275. BOOLEAN tasks_waiting;
  276. OS_EVENT *pevent_return;
  277. INT8U pcp; /* Priority ceiling priority */
  278. INT8U prio;
  279. OS_TCB *ptcb;
  280. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  281. OS_CPU_SR cpu_sr = 0u;
  282. #endif
  283. #ifdef OS_SAFETY_CRITICAL
  284. if (perr == (INT8U *)0) {
  285. OS_SAFETY_CRITICAL_EXCEPTION();
  286. return ((OS_EVENT *)0);
  287. }
  288. #endif
  289. #ifdef OS_SAFETY_CRITICAL_IEC61508
  290. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  291. OS_SAFETY_CRITICAL_EXCEPTION();
  292. *perr = OS_ERR_ILLEGAL_DEL_RUN_TIME;
  293. return ((OS_EVENT *)0);
  294. }
  295. #endif
  296. #if OS_ARG_CHK_EN > 0u
  297. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  298. *perr = OS_ERR_PEVENT_NULL;
  299. return (pevent);
  300. }
  301. #endif
  302. OS_TRACE_MUTEX_DEL_ENTER(pevent, opt);
  303. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  304. *perr = OS_ERR_EVENT_TYPE;
  305. OS_TRACE_MUTEX_DEL_EXIT(*perr);
  306. return (pevent);
  307. }
  308. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  309. *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  310. OS_TRACE_MUTEX_DEL_EXIT(*perr);
  311. return (pevent);
  312. }
  313. OS_ENTER_CRITICAL();
  314. if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on mutex */
  315. tasks_waiting = OS_TRUE; /* Yes */
  316. } else {
  317. tasks_waiting = OS_FALSE; /* No */
  318. }
  319. switch (opt) {
  320. case OS_DEL_NO_PEND: /* DELETE MUTEX ONLY IF NO TASK WAITING --- */
  321. if (tasks_waiting == OS_FALSE) {
  322. #if OS_EVENT_NAME_EN > 0u
  323. pevent->OSEventName = (INT8U *)(void *)"?";
  324. #endif
  325. pcp = (INT8U)(pevent->OSEventCnt >> 8u);
  326. if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
  327. OSTCBPrioTbl[pcp] = (OS_TCB *)0; /* Free up the PCP */
  328. }
  329. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  330. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  331. pevent->OSEventCnt = 0u;
  332. OSEventFreeList = pevent;
  333. OS_EXIT_CRITICAL();
  334. *perr = OS_ERR_NONE;
  335. pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
  336. } else {
  337. OS_EXIT_CRITICAL();
  338. *perr = OS_ERR_TASK_WAITING;
  339. pevent_return = pevent;
  340. }
  341. break;
  342. case OS_DEL_ALWAYS: /* ALWAYS DELETE THE MUTEX ---------------- */
  343. pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP of mutex */
  344. if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
  345. prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's orig prio */
  346. ptcb = (OS_TCB *)pevent->OSEventPtr;
  347. if (ptcb != (OS_TCB *)0) { /* See if any task owns the mutex */
  348. if (ptcb->OSTCBPrio == pcp) { /* See if original prio was changed */
  349. OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(OSTCBCur, prio);
  350. OSMutex_RdyAtPrio(ptcb, prio); /* Yes, Restore the task's original prio */
  351. }
  352. }
  353. }
  354. while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for mutex */
  355. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_ABORT);
  356. }
  357. #if OS_EVENT_NAME_EN > 0u
  358. pevent->OSEventName = (INT8U *)(void *)"?";
  359. #endif
  360. pcp = (INT8U)(pevent->OSEventCnt >> 8u);
  361. if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
  362. OSTCBPrioTbl[pcp] = (OS_TCB *)0; /* Free up the PCP */
  363. }
  364. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  365. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  366. pevent->OSEventCnt = 0u;
  367. OSEventFreeList = pevent; /* Get next free event control block */
  368. OS_EXIT_CRITICAL();
  369. if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
  370. OS_Sched(); /* Find highest priority task ready to run */
  371. }
  372. *perr = OS_ERR_NONE;
  373. pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
  374. break;
  375. default:
  376. OS_EXIT_CRITICAL();
  377. *perr = OS_ERR_INVALID_OPT;
  378. pevent_return = pevent;
  379. break;
  380. }
  381. OS_TRACE_MUTEX_DEL_EXIT(*perr);
  382. return (pevent_return);
  383. }
  384. #endif
  385. /*
  386. *********************************************************************************************************
  387. * PEND ON MUTUAL EXCLUSION SEMAPHORE
  388. *
  389. * Description: This function waits for a mutual exclusion semaphore.
  390. *
  391. * Arguments : pevent is a pointer to the event control block associated with the desired
  392. * mutex.
  393. *
  394. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  395. * wait for the resource up to the amount of time specified by this argument.
  396. * If you specify 0, however, your task will wait forever at the specified
  397. * mutex or, until the resource becomes available.
  398. *
  399. * perr is a pointer to where an error message will be deposited. Possible error
  400. * messages are:
  401. * OS_ERR_NONE The call was successful and your task owns the mutex
  402. * OS_ERR_TIMEOUT The mutex was not available within the specified 'timeout'.
  403. * OS_ERR_PEND_ABORT The wait on the mutex was aborted.
  404. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
  405. * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  406. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  407. * would lead to a suspension.
  408. * OS_ERR_PCP_LOWER If the priority of the task that owns the Mutex is
  409. * HIGHER (i.e. a lower number) than the PCP. This error
  410. * indicates that you did not set the PCP higher (lower
  411. * number) than ALL the tasks that compete for the Mutex.
  412. * Unfortunately, this is something that could not be
  413. * detected when the Mutex is created because we don't know
  414. * what tasks will be using the Mutex.
  415. * OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
  416. *
  417. * Returns : none
  418. *
  419. * Note(s) : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex.
  420. *
  421. * 2) You MUST NOT change the priority of the task that owns the mutex
  422. *********************************************************************************************************
  423. */
  424. void OSMutexPend (OS_EVENT *pevent,
  425. INT32U timeout,
  426. INT8U *perr)
  427. {
  428. INT8U pcp; /* Priority Ceiling Priority (PCP) */
  429. INT8U mprio; /* Mutex owner priority */
  430. BOOLEAN rdy; /* Flag indicating task was ready */
  431. OS_TCB *ptcb;
  432. OS_EVENT *pevent2;
  433. INT8U y;
  434. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  435. OS_CPU_SR cpu_sr = 0u;
  436. #endif
  437. #ifdef OS_SAFETY_CRITICAL
  438. if (perr == (INT8U *)0) {
  439. OS_SAFETY_CRITICAL_EXCEPTION();
  440. return;
  441. }
  442. #endif
  443. #if OS_ARG_CHK_EN > 0u
  444. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  445. *perr = OS_ERR_PEVENT_NULL;
  446. return;
  447. }
  448. #endif
  449. OS_TRACE_MUTEX_PEND_ENTER(pevent, timeout);
  450. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  451. *perr = OS_ERR_EVENT_TYPE;
  452. OS_TRACE_MUTEX_PEND_EXIT(*perr);
  453. return;
  454. }
  455. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  456. *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  457. OS_TRACE_MUTEX_PEND_EXIT(*perr);
  458. return;
  459. }
  460. if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */
  461. *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
  462. OS_TRACE_MUTEX_PEND_EXIT(*perr);
  463. return;
  464. }
  465. OS_ENTER_CRITICAL();
  466. pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */
  467. /* Is Mutex available? */
  468. if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
  469. pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */
  470. pevent->OSEventCnt |= (INT16U)OSTCBCur->OSTCBPrio; /* Save priority of owning task */
  471. pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */
  472. if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
  473. (OSTCBCur->OSTCBPrio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
  474. OS_EXIT_CRITICAL(); /* ... than current task! */
  475. *perr = OS_ERR_PCP_LOWER;
  476. } else {
  477. OS_EXIT_CRITICAL();
  478. *perr = OS_ERR_NONE;
  479. }
  480. OS_TRACE_MUTEX_PEND_EXIT(*perr);
  481. return;
  482. }
  483. if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
  484. mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */
  485. ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
  486. if (ptcb->OSTCBPrio > pcp) { /* Need to promote prio of owner?*/
  487. if (mprio > OSTCBCur->OSTCBPrio) {
  488. y = ptcb->OSTCBY;
  489. if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) { /* See if mutex owner is ready */
  490. OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/
  491. if (OSRdyTbl[y] == 0u) { /* ... list at current prio */
  492. OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
  493. }
  494. rdy = OS_TRUE;
  495. } else {
  496. pevent2 = ptcb->OSTCBEventPtr;
  497. if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */
  498. y = ptcb->OSTCBY;
  499. pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
  500. if (pevent2->OSEventTbl[y] == 0u) {
  501. pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
  502. }
  503. }
  504. rdy = OS_FALSE; /* No */
  505. }
  506. ptcb->OSTCBPrio = pcp; /* Change owner task prio to PCP */
  507. OS_TRACE_MUTEX_TASK_PRIO_INHERIT(ptcb, pcp);
  508. #if OS_LOWEST_PRIO <= 63u
  509. ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u);
  510. ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u);
  511. #else
  512. ptcb->OSTCBY = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);
  513. ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);
  514. #endif
  515. ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
  516. ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
  517. if (rdy == OS_TRUE) { /* If task was ready at owner's priority ...*/
  518. OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */
  519. OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  520. } else {
  521. pevent2 = ptcb->OSTCBEventPtr;
  522. if (pevent2 != (OS_EVENT *)0) { /* Add to event wait list */
  523. pevent2->OSEventGrp |= ptcb->OSTCBBitY;
  524. pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  525. }
  526. }
  527. OSTCBPrioTbl[pcp] = ptcb;
  528. }
  529. }
  530. }
  531. OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */
  532. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
  533. OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */
  534. OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  535. OS_EXIT_CRITICAL();
  536. OS_Sched(); /* Find next highest priority task ready */
  537. OS_ENTER_CRITICAL();
  538. switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
  539. case OS_STAT_PEND_OK:
  540. *perr = OS_ERR_NONE;
  541. break;
  542. case OS_STAT_PEND_ABORT:
  543. *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted getting mutex */
  544. break;
  545. case OS_STAT_PEND_TO:
  546. default:
  547. OS_EventTaskRemove(OSTCBCur, pevent);
  548. *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get mutex within TO */
  549. break;
  550. }
  551. OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
  552. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
  553. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
  554. #if (OS_EVENT_MULTI_EN > 0u)
  555. OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  556. OSTCBCur->OSTCBEventMultiRdy = (OS_EVENT *)0;
  557. #endif
  558. OS_EXIT_CRITICAL();
  559. OS_TRACE_MUTEX_PEND_EXIT(*perr);
  560. }
  561. /*
  562. *********************************************************************************************************
  563. * POST TO A MUTUAL EXCLUSION SEMAPHORE
  564. *
  565. * Description: This function signals a mutual exclusion semaphore
  566. *
  567. * Arguments : pevent is a pointer to the event control block associated with the desired
  568. * mutex.
  569. *
  570. * Returns : OS_ERR_NONE The call was successful and the mutex was signaled.
  571. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
  572. * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  573. * OS_ERR_POST_ISR Attempted to post from an ISR (not valid for MUTEXes)
  574. * OS_ERR_NOT_MUTEX_OWNER The task that did the post is NOT the owner of the MUTEX.
  575. * OS_ERR_PCP_LOWER If the priority of the new task that owns the Mutex is
  576. * HIGHER (i.e. a lower number) than the PCP. This error
  577. * indicates that you did not set the PCP higher (lower
  578. * number) than ALL the tasks that compete for the Mutex.
  579. * Unfortunately, this is something that could not be
  580. * detected when the Mutex is created because we don't know
  581. * what tasks will be using the Mutex.
  582. *********************************************************************************************************
  583. */
  584. INT8U OSMutexPost (OS_EVENT *pevent)
  585. {
  586. INT8U pcp; /* Priority ceiling priority */
  587. INT8U prio;
  588. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  589. OS_CPU_SR cpu_sr = 0u;
  590. #endif
  591. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  592. return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */
  593. }
  594. #if OS_ARG_CHK_EN > 0u
  595. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  596. return (OS_ERR_PEVENT_NULL);
  597. }
  598. #endif
  599. OS_TRACE_MUTEX_POST_ENTER(pevent);
  600. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  601. OS_TRACE_MUTEX_POST_EXIT(OS_ERR_EVENT_TYPE);
  602. return (OS_ERR_EVENT_TYPE);
  603. }
  604. OS_ENTER_CRITICAL();
  605. pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get priority ceiling priority of mutex */
  606. prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original priority */
  607. if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */
  608. OS_EXIT_CRITICAL();
  609. OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NOT_MUTEX_OWNER);
  610. return (OS_ERR_NOT_MUTEX_OWNER);
  611. }
  612. if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
  613. if (OSTCBCur->OSTCBPrio == pcp) { /* Did we have to raise current task's priority? */
  614. OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(OSTCBCur, prio);
  615. OSMutex_RdyAtPrio(OSTCBCur, prio); /* Restore the task's original priority */
  616. }
  617. OSTCBPrioTbl[pcp] = OS_TCB_RESERVED; /* Reserve table entry */
  618. }
  619. if (pevent->OSEventGrp != 0u) { /* Any task waiting for the mutex? */
  620. /* Yes, Make HPT waiting for mutex ready */
  621. prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
  622. pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */
  623. pevent->OSEventCnt |= (INT16U)prio;
  624. pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to new mutex owner's OS_TCB */
  625. if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
  626. (prio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
  627. OS_EXIT_CRITICAL(); /* ... than current task! */
  628. OS_Sched(); /* Find highest priority task ready to run */
  629. OS_TRACE_MUTEX_POST_EXIT(OS_ERR_PCP_LOWER);
  630. return (OS_ERR_PCP_LOWER);
  631. } else {
  632. OS_EXIT_CRITICAL();
  633. OS_Sched(); /* Find highest priority task ready to run */
  634. OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE);
  635. return (OS_ERR_NONE);
  636. }
  637. }
  638. pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */
  639. pevent->OSEventPtr = (void *)0;
  640. OS_EXIT_CRITICAL();
  641. OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE);
  642. return (OS_ERR_NONE);
  643. }
  644. /*
  645. *********************************************************************************************************
  646. * QUERY A MUTUAL EXCLUSION SEMAPHORE
  647. *
  648. * Description: This function obtains information about a mutex
  649. *
  650. * Arguments : pevent is a pointer to the event control block associated with the desired mutex
  651. *
  652. * p_mutex_data is a pointer to a structure that will contain information about the mutex
  653. *
  654. * Returns : OS_ERR_NONE The call was successful and the message was sent
  655. * OS_ERR_QUERY_ISR If you called this function from an ISR
  656. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  657. * OS_ERR_PDATA_NULL If 'p_mutex_data' is a NULL pointer
  658. * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mutex.
  659. *********************************************************************************************************
  660. */
  661. #if OS_MUTEX_QUERY_EN > 0u
  662. INT8U OSMutexQuery (OS_EVENT *pevent,
  663. OS_MUTEX_DATA *p_mutex_data)
  664. {
  665. INT8U i;
  666. OS_PRIO *psrc;
  667. OS_PRIO *pdest;
  668. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  669. OS_CPU_SR cpu_sr = 0u;
  670. #endif
  671. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  672. return (OS_ERR_QUERY_ISR); /* ... can't QUERY mutex from an ISR */
  673. }
  674. #if OS_ARG_CHK_EN > 0u
  675. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  676. return (OS_ERR_PEVENT_NULL);
  677. }
  678. if (p_mutex_data == (OS_MUTEX_DATA *)0) { /* Validate 'p_mutex_data' */
  679. return (OS_ERR_PDATA_NULL);
  680. }
  681. #endif
  682. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  683. return (OS_ERR_EVENT_TYPE);
  684. }
  685. OS_ENTER_CRITICAL();
  686. p_mutex_data->OSMutexPCP = (INT8U)(pevent->OSEventCnt >> 8u);
  687. p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
  688. if (p_mutex_data->OSOwnerPrio == 0xFFu) {
  689. p_mutex_data->OSValue = OS_TRUE;
  690. } else {
  691. p_mutex_data->OSValue = OS_FALSE;
  692. }
  693. p_mutex_data->OSEventGrp = pevent->OSEventGrp; /* Copy wait list */
  694. psrc = &pevent->OSEventTbl[0];
  695. pdest = &p_mutex_data->OSEventTbl[0];
  696. for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
  697. *pdest++ = *psrc++;
  698. }
  699. OS_EXIT_CRITICAL();
  700. return (OS_ERR_NONE);
  701. }
  702. #endif /* OS_MUTEX_QUERY_EN */
  703. /*
  704. *********************************************************************************************************
  705. * RESTORE A TASK BACK TO ITS ORIGINAL PRIORITY
  706. *
  707. * Description: This function makes a task ready at the specified priority
  708. *
  709. * Arguments : ptcb is a pointer to OS_TCB of the task to make ready
  710. *
  711. * prio is the desired priority
  712. *
  713. * Returns : none
  714. *********************************************************************************************************
  715. */
  716. static void OSMutex_RdyAtPrio (OS_TCB *ptcb,
  717. INT8U prio)
  718. {
  719. INT8U y;
  720. y = ptcb->OSTCBY; /* Remove owner from ready list at 'pcp' */
  721. OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
  722. OS_TRACE_TASK_SUSPENDED(ptcb);
  723. if (OSRdyTbl[y] == 0u) {
  724. OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
  725. }
  726. ptcb->OSTCBPrio = prio;
  727. OSPrioCur = prio; /* The current task is now at this priority */
  728. #if OS_LOWEST_PRIO <= 63u
  729. ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 3u) & 0x07u);
  730. ptcb->OSTCBX = (INT8U)(prio & 0x07u);
  731. #else
  732. ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0x0Fu);
  733. ptcb->OSTCBX = (INT8U) (prio & 0x0Fu);
  734. #endif
  735. ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
  736. ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
  737. OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready at original priority */
  738. OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  739. OSTCBPrioTbl[prio] = ptcb;
  740. OS_TRACE_TASK_READY(ptcb);
  741. }
  742. #endif /* OS_MUTEX_EN */
  743. #endif /* OS_MUTEX_C */