/src/compiler/ucos-vs2008/UCOS_SIM/src/ucosii/os_mutex.c

http://ftk.googlecode.com/ · C · 603 lines · 390 code · 34 blank · 179 comment · 94 complexity · 09fbeec509c78b1996a94780188c5569 MD5 · raw file

  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * MUTUAL EXCLUSION SEMAPHORE MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2005, Jean J. Labrosse, Weston, FL
  8. * All Rights Reserved
  9. *
  10. * File : OS_MUTEX.C
  11. * By : Jean J. Labrosse
  12. * Version : V2.80
  13. *********************************************************************************************************
  14. */
  15. #ifndef OS_MASTER_FILE
  16. #include <ucos_ii.h>
  17. #endif
  18. /*
  19. *********************************************************************************************************
  20. * LOCAL CONSTANTS
  21. *********************************************************************************************************
  22. */
  23. #define OS_MUTEX_KEEP_LOWER_8 0x00FFu
  24. #define OS_MUTEX_KEEP_UPPER_8 0xFF00u
  25. #define OS_MUTEX_AVAILABLE 0x00FFu
  26. #if OS_MUTEX_EN > 0
  27. /*
  28. *********************************************************************************************************
  29. * ACCEPT MUTUAL EXCLUSION SEMAPHORE
  30. *
  31. * Description: This function checks the mutual exclusion semaphore to see if a resource is available.
  32. * Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is
  33. * not available or the event did not occur.
  34. *
  35. * Arguments : pevent is a pointer to the event control block
  36. *
  37. * err is a pointer to an error code which will be returned to your application:
  38. * OS_NO_ERR if the call was successful.
  39. * OS_ERR_EVENT_TYPE if 'pevent' is not a pointer to a mutex
  40. * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  41. * OS_ERR_PEND_ISR if you called this function from an ISR
  42. *
  43. * Returns : == 1 if the resource is available, the mutual exclusion semaphore is acquired
  44. * == 0 a) if the resource is not available
  45. * b) you didn't pass a pointer to a mutual exclusion semaphore
  46. * c) you called this function from an ISR
  47. *
  48. * Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are
  49. * intended to be used by tasks only.
  50. *********************************************************************************************************
  51. */
  52. #if OS_MUTEX_ACCEPT_EN > 0
  53. INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err)
  54. {
  55. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  56. OS_CPU_SR cpu_sr = 0;
  57. #endif
  58. #if OS_ARG_CHK_EN > 0
  59. if (err == (INT8U *)0) { /* Validate 'err' */
  60. return (0);
  61. }
  62. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  63. *err = OS_ERR_PEVENT_NULL;
  64. return (0);
  65. }
  66. #endif
  67. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  68. *err = OS_ERR_EVENT_TYPE;
  69. return (0);
  70. }
  71. if (OSIntNesting > 0) { /* Make sure it's not called from an ISR */
  72. *err = OS_ERR_PEND_ISR;
  73. return (0);
  74. }
  75. OS_ENTER_CRITICAL(); /* Get value (0 or 1) of Mutex */
  76. if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
  77. pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Mask off LSByte (Acquire Mutex) */
  78. pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save current task priority in LSByte */
  79. pevent->OSEventPtr = (void *)OSTCBCur; /* Link TCB of task owning Mutex */
  80. OS_EXIT_CRITICAL();
  81. *err = OS_NO_ERR;
  82. return (1);
  83. }
  84. OS_EXIT_CRITICAL();
  85. *err = OS_NO_ERR;
  86. return (0);
  87. }
  88. #endif
  89. /*$PAGE*/
  90. /*
  91. *********************************************************************************************************
  92. * CREATE A MUTUAL EXCLUSION SEMAPHORE
  93. *
  94. * Description: This function creates a mutual exclusion semaphore.
  95. *
  96. * Arguments : prio is the priority to use when accessing the mutual exclusion semaphore. In
  97. * other words, when the semaphore is acquired and a higher priority task
  98. * attempts to obtain the semaphore then the priority of the task owning the
  99. * semaphore is raised to this priority. It is assumed that you will specify
  100. * a priority that is LOWER in value than ANY of the tasks competing for the
  101. * mutex.
  102. *
  103. * err is a pointer to an error code which will be returned to your application:
  104. * OS_NO_ERR if the call was successful.
  105. * OS_ERR_CREATE_ISR if you attempted to create a MUTEX from an ISR
  106. * OS_PRIO_EXIST if a task at the priority inheritance priority
  107. * already exist.
  108. * OS_ERR_PEVENT_NULL No more event control blocks available.
  109. * OS_PRIO_INVALID if the priority you specify is higher that the
  110. * maximum allowed (i.e. > OS_LOWEST_PRIO)
  111. *
  112. * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
  113. * created mutex.
  114. * == (void *)0 if an error is detected.
  115. *
  116. * Note(s) : 1) The LEAST significant 8 bits of '.OSEventCnt' are used to hold the priority number
  117. * of the task owning the mutex or 0xFF if no task owns the mutex.
  118. * 2) The MOST significant 8 bits of '.OSEventCnt' are used to hold the priority number
  119. * to use to reduce priority inversion.
  120. *********************************************************************************************************
  121. */
  122. OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)
  123. {
  124. OS_EVENT *pevent;
  125. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  126. OS_CPU_SR cpu_sr = 0;
  127. #endif
  128. #if OS_ARG_CHK_EN > 0
  129. if (err == (INT8U *)0) { /* Validate 'err' */
  130. return ((OS_EVENT *)0);
  131. }
  132. if (prio >= OS_LOWEST_PRIO) { /* Validate PIP */
  133. *err = OS_PRIO_INVALID;
  134. return ((OS_EVENT *)0);
  135. }
  136. #endif
  137. if (OSIntNesting > 0) { /* See if called from ISR ... */
  138. *err = OS_ERR_CREATE_ISR; /* ... can't CREATE mutex from an ISR */
  139. return ((OS_EVENT *)0);
  140. }
  141. OS_ENTER_CRITICAL();
  142. if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* Mutex priority must not already exist */
  143. OS_EXIT_CRITICAL(); /* Task already exist at priority ... */
  144. *err = OS_PRIO_EXIST; /* ... inheritance priority */
  145. return ((OS_EVENT *)0);
  146. }
  147. OSTCBPrioTbl[prio] = (OS_TCB *)1; /* Reserve the table entry */
  148. pevent = OSEventFreeList; /* Get next free event control block */
  149. if (pevent == (OS_EVENT *)0) { /* See if an ECB was available */
  150. OSTCBPrioTbl[prio] = (OS_TCB *)0; /* No, Release the table entry */
  151. OS_EXIT_CRITICAL();
  152. *err = OS_ERR_PEVENT_NULL; /* No more event control blocks */
  153. return (pevent);
  154. }
  155. OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* Adjust the free list */
  156. OS_EXIT_CRITICAL();
  157. pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
  158. pevent->OSEventCnt = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE; /* Resource is avail. */
  159. pevent->OSEventPtr = (void *)0; /* No task owning the mutex */
  160. #if OS_EVENT_NAME_SIZE > 1
  161. pevent->OSEventName[0] = '?';
  162. pevent->OSEventName[1] = OS_ASCII_NUL;
  163. #endif
  164. OS_EventWaitListInit(pevent);
  165. *err = OS_NO_ERR;
  166. return (pevent);
  167. }
  168. /*$PAGE*/
  169. /*
  170. *********************************************************************************************************
  171. * DELETE A MUTEX
  172. *
  173. * Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it.
  174. *
  175. * Arguments : pevent is a pointer to the event control block associated with the desired mutex.
  176. *
  177. * opt determines delete options as follows:
  178. * opt == OS_DEL_NO_PEND Delete mutex ONLY if no task pending
  179. * opt == OS_DEL_ALWAYS Deletes the mutex even if tasks are waiting.
  180. * In this case, all the tasks pending will be readied.
  181. *
  182. * err is a pointer to an error code that can contain one of the following values:
  183. * OS_NO_ERR The call was successful and the mutex was deleted
  184. * OS_ERR_DEL_ISR If you attempted to delete the MUTEX from an ISR
  185. * OS_ERR_INVALID_OPT An invalid option was specified
  186. * OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex
  187. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
  188. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  189. *
  190. * Returns : pevent upon error
  191. * (OS_EVENT *)0 if the mutex was successfully deleted.
  192. *
  193. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  194. * the mutex MUST check the return code of OSMutexPend().
  195. * 2) This call can potentially disable interrupts for a long time. The interrupt disable
  196. * time is directly proportional to the number of tasks waiting on the mutex.
  197. * 3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the
  198. * resource(s) will no longer be guarded by the mutex.
  199. *********************************************************************************************************
  200. */
  201. #if OS_MUTEX_DEL_EN
  202. OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  203. {
  204. BOOLEAN tasks_waiting;
  205. OS_EVENT *pevent_return;
  206. INT8U pip;
  207. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  208. OS_CPU_SR cpu_sr = 0;
  209. #endif
  210. #if OS_ARG_CHK_EN > 0
  211. if (err == (INT8U *)0) { /* Validate 'err' */
  212. return ((OS_EVENT *)0);
  213. }
  214. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  215. *err = OS_ERR_PEVENT_NULL;
  216. return ((OS_EVENT *)0);
  217. }
  218. #endif
  219. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  220. *err = OS_ERR_EVENT_TYPE;
  221. return (pevent);
  222. }
  223. if (OSIntNesting > 0) { /* See if called from ISR ... */
  224. *err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  225. return (pevent);
  226. }
  227. OS_ENTER_CRITICAL();
  228. if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on mutex */
  229. tasks_waiting = TRUE; /* Yes */
  230. } else {
  231. tasks_waiting = FALSE; /* No */
  232. }
  233. switch (opt) {
  234. case OS_DEL_NO_PEND: /* Delete mutex only if no task waiting */
  235. if (tasks_waiting == FALSE) {
  236. #if OS_EVENT_NAME_SIZE > 1
  237. pevent->OSEventName[0] = '?'; /* Unknown name */
  238. pevent->OSEventName[1] = OS_ASCII_NUL;
  239. #endif
  240. pip = (INT8U)(pevent->OSEventCnt >> 8);
  241. OSTCBPrioTbl[pip] = (OS_TCB *)0; /* Free up the PIP */
  242. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  243. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  244. pevent->OSEventCnt = 0;
  245. OSEventFreeList = pevent;
  246. OS_EXIT_CRITICAL();
  247. *err = OS_NO_ERR;
  248. pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
  249. } else {
  250. OS_EXIT_CRITICAL();
  251. *err = OS_ERR_TASK_WAITING;
  252. pevent_return = pevent;
  253. }
  254. break;
  255. case OS_DEL_ALWAYS: /* Always delete the mutex */
  256. while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for mutex */
  257. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
  258. }
  259. #if OS_EVENT_NAME_SIZE > 1
  260. pevent->OSEventName[0] = '?'; /* Unknown name */
  261. pevent->OSEventName[1] = OS_ASCII_NUL;
  262. #endif
  263. pip = (INT8U)(pevent->OSEventCnt >> 8);
  264. OSTCBPrioTbl[pip] = (OS_TCB *)0; /* Free up the PIP */
  265. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  266. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  267. pevent->OSEventCnt = 0;
  268. OSEventFreeList = pevent; /* Get next free event control block */
  269. OS_EXIT_CRITICAL();
  270. if (tasks_waiting == TRUE) { /* Reschedule only if task(s) were waiting */
  271. OS_Sched(); /* Find highest priority task ready to run */
  272. }
  273. *err = OS_NO_ERR;
  274. pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
  275. break;
  276. default:
  277. OS_EXIT_CRITICAL();
  278. *err = OS_ERR_INVALID_OPT;
  279. pevent_return = pevent;
  280. break;
  281. }
  282. return (pevent_return);
  283. }
  284. #endif
  285. /*$PAGE*/
  286. /*
  287. *********************************************************************************************************
  288. * PEND ON MUTUAL EXCLUSION SEMAPHORE
  289. *
  290. * Description: This function waits for a mutual exclusion semaphore.
  291. *
  292. * Arguments : pevent is a pointer to the event control block associated with the desired
  293. * mutex.
  294. *
  295. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  296. * wait for the resource up to the amount of time specified by this argument.
  297. * If you specify 0, however, your task will wait forever at the specified
  298. * mutex or, until the resource becomes available.
  299. *
  300. * err is a pointer to where an error message will be deposited. Possible error
  301. * messages are:
  302. * OS_NO_ERR The call was successful and your task owns the mutex
  303. * OS_TIMEOUT The mutex was not available within the specified time.
  304. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
  305. * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  306. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  307. * would lead to a suspension.
  308. * OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is
  309. * HIGHER (i.e. a lower number) than the PIP. This error
  310. * indicates that you did not set the PIP higher (lower
  311. * number) than ALL the tasks that compete for the Mutex.
  312. * Unfortunately, this is something that could not be
  313. * detected when the Mutex is created because we don't know
  314. * what tasks will be using the Mutex.
  315. *
  316. * Returns : none
  317. *
  318. * Note(s) : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex.
  319. * 2) You MUST NOT change the priority of the task that owns the mutex
  320. *********************************************************************************************************
  321. */
  322. void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  323. {
  324. INT8U pip; /* Priority Inheritance Priority (PIP) */
  325. INT8U mprio; /* Mutex owner priority */
  326. BOOLEAN rdy; /* Flag indicating task was ready */
  327. OS_TCB *ptcb;
  328. OS_EVENT *pevent2;
  329. INT8U y;
  330. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  331. OS_CPU_SR cpu_sr = 0;
  332. #endif
  333. #if OS_ARG_CHK_EN > 0
  334. if (err == (INT8U *)0) { /* Validate 'err' */
  335. return;
  336. }
  337. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  338. *err = OS_ERR_PEVENT_NULL;
  339. return;
  340. }
  341. #endif
  342. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  343. *err = OS_ERR_EVENT_TYPE;
  344. return;
  345. }
  346. if (OSIntNesting > 0) { /* See if called from ISR ... */
  347. *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  348. return;
  349. }
  350. OS_ENTER_CRITICAL();
  351. pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get PIP from mutex */
  352. /* Is Mutex available? */
  353. if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
  354. pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */
  355. pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */
  356. pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */
  357. if (OSTCBCur->OSTCBPrio <= pip) { /* PIP 'must' have a SMALLER prio ... */
  358. OS_EXIT_CRITICAL(); /* ... than current task! */
  359. *err = OS_ERR_PIP_LOWER;
  360. } else {
  361. OS_EXIT_CRITICAL();
  362. *err = OS_NO_ERR;
  363. }
  364. return;
  365. }
  366. mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* No, Get priority of mutex owner */
  367. ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
  368. if (ptcb->OSTCBPrio > pip) { /* Need to promote prio of owner?*/
  369. if (mprio > OSTCBCur->OSTCBPrio) {
  370. y = ptcb->OSTCBY;
  371. if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0) { /* See if mutex owner is ready */
  372. OSRdyTbl[y] &= ~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/
  373. if (OSRdyTbl[y] == 0) { /* ... list at current prio */
  374. OSRdyGrp &= ~ptcb->OSTCBBitY;
  375. }
  376. rdy = TRUE;
  377. } else {
  378. pevent2 = ptcb->OSTCBEventPtr;
  379. if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */
  380. if ((pevent2->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
  381. pevent2->OSEventGrp &= ~ptcb->OSTCBBitY;
  382. }
  383. }
  384. rdy = FALSE; /* No */
  385. }
  386. ptcb->OSTCBPrio = pip; /* Change owner task prio to PIP */
  387. #if OS_LOWEST_PRIO <= 63
  388. ptcb->OSTCBY = ptcb->OSTCBPrio >> 3;
  389. ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07;
  390. #else
  391. ptcb->OSTCBY = (ptcb->OSTCBPrio >> 4) & 0xFF;
  392. ptcb->OSTCBX = ptcb->OSTCBPrio & 0x0F;
  393. #endif
  394. ptcb->OSTCBBitY = 1 << ptcb->OSTCBY;
  395. ptcb->OSTCBBitX = 1 << ptcb->OSTCBX;
  396. if (rdy == TRUE) { /* If task was ready at owner's priority ...*/
  397. OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */
  398. OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  399. } else {
  400. pevent2 = ptcb->OSTCBEventPtr;
  401. if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */
  402. pevent2->OSEventGrp |= ptcb->OSTCBBitY;
  403. pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  404. }
  405. }
  406. OSTCBPrioTbl[pip] = ptcb;
  407. }
  408. }
  409. OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */
  410. OSTCBCur->OSTCBPendTO = FALSE;
  411. OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */
  412. OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  413. OS_EXIT_CRITICAL();
  414. OS_Sched(); /* Find next highest priority task ready */
  415. OS_ENTER_CRITICAL();
  416. if (OSTCBCur->OSTCBPendTO == TRUE) { /* See if we timed out during the pend */
  417. OS_EventTO(pevent);
  418. OS_EXIT_CRITICAL();
  419. *err = OS_TIMEOUT; /* Indicate that we didn't get mutex within TO */
  420. return;
  421. }
  422. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  423. OS_EXIT_CRITICAL();
  424. *err = OS_NO_ERR;
  425. }
  426. /*$PAGE*/
  427. /*
  428. *********************************************************************************************************
  429. * POST TO A MUTUAL EXCLUSION SEMAPHORE
  430. *
  431. * Description: This function signals a mutual exclusion semaphore
  432. *
  433. * Arguments : pevent is a pointer to the event control block associated with the desired
  434. * mutex.
  435. *
  436. * Returns : OS_NO_ERR The call was successful and the mutex was signaled.
  437. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
  438. * OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  439. * OS_ERR_POST_ISR Attempted to post from an ISR (not valid for MUTEXes)
  440. * OS_ERR_NOT_MUTEX_OWNER The task that did the post is NOT the owner of the MUTEX.
  441. *********************************************************************************************************
  442. */
  443. INT8U OSMutexPost (OS_EVENT *pevent)
  444. {
  445. INT8U pip; /* Priority inheritance priority */
  446. INT8U prio;
  447. INT8U y;
  448. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  449. OS_CPU_SR cpu_sr = 0;
  450. #endif
  451. if (OSIntNesting > 0) { /* See if called from ISR ... */
  452. return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */
  453. }
  454. #if OS_ARG_CHK_EN > 0
  455. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  456. return (OS_ERR_PEVENT_NULL);
  457. }
  458. #endif
  459. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  460. return (OS_ERR_EVENT_TYPE);
  461. }
  462. OS_ENTER_CRITICAL();
  463. pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get priority inheritance priority of mutex */
  464. prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original priority */
  465. if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */
  466. OS_EXIT_CRITICAL();
  467. return (OS_ERR_NOT_MUTEX_OWNER);
  468. }
  469. if (OSTCBCur->OSTCBPrio == pip) { /* Did we have to raise current task's priority? */
  470. y = OSTCBCur->OSTCBY; /* Yes, Return to original priority */
  471. OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX; /* Remove owner from ready list at 'pip' */
  472. if (OSRdyTbl[y] == 0) {
  473. OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
  474. }
  475. OSTCBCur->OSTCBPrio = prio;
  476. #if OS_LOWEST_PRIO <= 63
  477. OSTCBCur->OSTCBY = prio >> 3;
  478. OSTCBCur->OSTCBX = prio & 0x07;
  479. #else
  480. OSTCBCur->OSTCBY = (prio >> 4) & 0xFF;
  481. OSTCBCur->OSTCBX = prio & 0x0F;
  482. #endif
  483. OSTCBCur->OSTCBBitY = 1 << OSTCBCur->OSTCBY;
  484. OSTCBCur->OSTCBBitX = 1 << OSTCBCur->OSTCBX;
  485. OSRdyGrp |= OSTCBCur->OSTCBBitY;
  486. OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
  487. OSTCBPrioTbl[prio] = OSTCBCur;
  488. }
  489. OSTCBPrioTbl[pip] = (OS_TCB *)1; /* Reserve table entry */
  490. if (pevent->OSEventGrp != 0) { /* Any task waiting for the mutex? */
  491. /* Yes, Make HPT waiting for mutex ready */
  492. prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
  493. pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */
  494. pevent->OSEventCnt |= prio;
  495. pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to mutex owner's OS_TCB */
  496. OS_EXIT_CRITICAL();
  497. OS_Sched(); /* Find highest priority task ready to run */
  498. return (OS_NO_ERR);
  499. }
  500. pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */
  501. pevent->OSEventPtr = (void *)0;
  502. OS_EXIT_CRITICAL();
  503. return (OS_NO_ERR);
  504. }
  505. /*$PAGE*/
  506. /*
  507. *********************************************************************************************************
  508. * QUERY A MUTUAL EXCLUSION SEMAPHORE
  509. *
  510. * Description: This function obtains information about a mutex
  511. *
  512. * Arguments : pevent is a pointer to the event control block associated with the desired mutex
  513. *
  514. * p_mutex_data is a pointer to a structure that will contain information about the mutex
  515. *
  516. * Returns : OS_NO_ERR The call was successful and the message was sent
  517. * OS_ERR_QUERY_ISR If you called this function from an ISR
  518. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  519. * OS_ERR_PDATA_NULL If 'p_mutex_data' is a NULL pointer
  520. * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mutex.
  521. *********************************************************************************************************
  522. */
  523. #if OS_MUTEX_QUERY_EN > 0
  524. INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data)
  525. {
  526. INT8U i;
  527. #if OS_LOWEST_PRIO <= 63
  528. INT8U *psrc;
  529. INT8U *pdest;
  530. #else
  531. INT16U *psrc;
  532. INT16U *pdest;
  533. #endif
  534. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  535. OS_CPU_SR cpu_sr = 0;
  536. #endif
  537. if (OSIntNesting > 0) { /* See if called from ISR ... */
  538. return (OS_ERR_QUERY_ISR); /* ... can't QUERY mutex from an ISR */
  539. }
  540. #if OS_ARG_CHK_EN > 0
  541. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  542. return (OS_ERR_PEVENT_NULL);
  543. }
  544. if (p_mutex_data == (OS_MUTEX_DATA *)0) { /* Validate 'p_mutex_data' */
  545. return (OS_ERR_PDATA_NULL);
  546. }
  547. #endif
  548. if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
  549. return (OS_ERR_EVENT_TYPE);
  550. }
  551. OS_ENTER_CRITICAL();
  552. p_mutex_data->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8);
  553. p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
  554. if (p_mutex_data->OSOwnerPrio == 0xFF) {
  555. p_mutex_data->OSValue = 1;
  556. } else {
  557. p_mutex_data->OSValue = 0;
  558. }
  559. p_mutex_data->OSEventGrp = pevent->OSEventGrp; /* Copy wait list */
  560. psrc = &pevent->OSEventTbl[0];
  561. pdest = &p_mutex_data->OSEventTbl[0];
  562. for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  563. *pdest++ = *psrc++;
  564. }
  565. OS_EXIT_CRITICAL();
  566. return (OS_NO_ERR);
  567. }
  568. #endif /* OS_MUTEX_QUERY_EN */
  569. #endif /* OS_MUTEX_EN */