rt_Mutex.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*----------------------------------------------------------------------------
  2. * CMSIS-RTOS - RTX
  3. *----------------------------------------------------------------------------
  4. * Name: RT_MUTEX.C
  5. * Purpose: Implements mutex synchronization objects
  6. * Rev.: V4.82
  7. *----------------------------------------------------------------------------
  8. *
  9. * Copyright (c) 1999-2009 KEIL, 2009-2017 ARM Germany GmbH. All rights reserved.
  10. *
  11. * SPDX-License-Identifier: Apache-2.0
  12. *
  13. * Licensed under the Apache License, Version 2.0 (the License); you may
  14. * not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  21. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. *---------------------------------------------------------------------------*/
  25. #include "rt_TypeDef.h"
  26. #include "RTX_Config.h"
  27. #include "rt_List.h"
  28. #include "rt_Task.h"
  29. #include "rt_Mutex.h"
  30. #include "rt_HAL_CM.h"
  31. /*----------------------------------------------------------------------------
  32. * Functions
  33. *---------------------------------------------------------------------------*/
  34. /*--------------------------- rt_mut_init -----------------------------------*/
  35. void rt_mut_init (OS_ID mutex) {
  36. /* Initialize a mutex object */
  37. P_MUCB p_MCB = mutex;
  38. p_MCB->cb_type = MUCB;
  39. p_MCB->level = 0U;
  40. p_MCB->p_lnk = NULL;
  41. p_MCB->owner = NULL;
  42. p_MCB->p_mlnk = NULL;
  43. }
  44. /*--------------------------- rt_mut_delete ---------------------------------*/
  45. #ifdef __CMSIS_RTOS
  46. OS_RESULT rt_mut_delete (OS_ID mutex) {
  47. /* Delete a mutex object */
  48. P_MUCB p_MCB = mutex;
  49. P_TCB p_TCB;
  50. P_MUCB p_mlnk;
  51. U8 prio;
  52. if (p_MCB->level != 0U) {
  53. p_TCB = p_MCB->owner;
  54. /* Remove mutex from task mutex owner list. */
  55. p_mlnk = p_TCB->p_mlnk;
  56. if (p_mlnk == p_MCB) {
  57. p_TCB->p_mlnk = p_MCB->p_mlnk;
  58. }
  59. else {
  60. while (p_mlnk) {
  61. if (p_mlnk->p_mlnk == p_MCB) {
  62. p_mlnk->p_mlnk = p_MCB->p_mlnk;
  63. break;
  64. }
  65. p_mlnk = p_mlnk->p_mlnk;
  66. }
  67. }
  68. /* Restore owner task's priority. */
  69. prio = p_TCB->prio_base;
  70. p_mlnk = p_TCB->p_mlnk;
  71. while (p_mlnk) {
  72. if ((p_mlnk->p_lnk != NULL) && (p_mlnk->p_lnk->prio > prio)) {
  73. /* A task with higher priority is waiting for mutex. */
  74. prio = p_mlnk->p_lnk->prio;
  75. }
  76. p_mlnk = p_mlnk->p_mlnk;
  77. }
  78. if (p_TCB->prio != prio) {
  79. p_TCB->prio = prio;
  80. if (p_TCB != os_tsk.run) {
  81. rt_resort_prio (p_TCB);
  82. }
  83. }
  84. }
  85. while (p_MCB->p_lnk != NULL) {
  86. /* A task is waiting for mutex. */
  87. p_TCB = rt_get_first ((P_XCB)p_MCB);
  88. rt_ret_val(p_TCB, 0U/*osOK*/);
  89. rt_rmv_dly(p_TCB);
  90. p_TCB->state = READY;
  91. rt_put_prio (&os_rdy, p_TCB);
  92. }
  93. if ((os_rdy.p_lnk != NULL) && (os_rdy.p_lnk->prio > os_tsk.run->prio)) {
  94. /* preempt running task */
  95. rt_put_prio (&os_rdy, os_tsk.run);
  96. os_tsk.run->state = READY;
  97. rt_dispatch (NULL);
  98. }
  99. p_MCB->cb_type = 0U;
  100. return (OS_R_OK);
  101. }
  102. #endif
  103. /*--------------------------- rt_mut_release --------------------------------*/
  104. OS_RESULT rt_mut_release (OS_ID mutex) {
  105. /* Release a mutex object */
  106. P_MUCB p_MCB = mutex;
  107. P_TCB p_TCB;
  108. P_MUCB p_mlnk;
  109. U8 prio;
  110. if ((p_MCB->level == 0U) || (p_MCB->owner != os_tsk.run)) {
  111. /* Unbalanced mutex release or task is not the owner */
  112. return (OS_R_NOK);
  113. }
  114. if (--p_MCB->level != 0U) {
  115. return (OS_R_OK);
  116. }
  117. /* Remove mutex from task mutex owner list. */
  118. p_mlnk = os_tsk.run->p_mlnk;
  119. if (p_mlnk == p_MCB) {
  120. os_tsk.run->p_mlnk = p_MCB->p_mlnk;
  121. }
  122. else {
  123. while (p_mlnk) {
  124. if (p_mlnk->p_mlnk == p_MCB) {
  125. p_mlnk->p_mlnk = p_MCB->p_mlnk;
  126. break;
  127. }
  128. p_mlnk = p_mlnk->p_mlnk;
  129. }
  130. }
  131. /* Restore owner task's priority. */
  132. prio = os_tsk.run->prio_base;
  133. p_mlnk = os_tsk.run->p_mlnk;
  134. while (p_mlnk) {
  135. if ((p_mlnk->p_lnk != NULL) && (p_mlnk->p_lnk->prio > prio)) {
  136. /* A task with higher priority is waiting for mutex. */
  137. prio = p_mlnk->p_lnk->prio;
  138. }
  139. p_mlnk = p_mlnk->p_mlnk;
  140. }
  141. os_tsk.run->prio = prio;
  142. if (p_MCB->p_lnk != NULL) {
  143. /* A task is waiting for mutex. */
  144. p_TCB = rt_get_first ((P_XCB)p_MCB);
  145. #ifdef __CMSIS_RTOS
  146. rt_ret_val(p_TCB, 0U/*osOK*/);
  147. #else
  148. rt_ret_val(p_TCB, OS_R_MUT);
  149. #endif
  150. rt_rmv_dly (p_TCB);
  151. /* A waiting task becomes the owner of this mutex. */
  152. p_MCB->level = 1U;
  153. p_MCB->owner = p_TCB;
  154. p_MCB->p_mlnk = p_TCB->p_mlnk;
  155. p_TCB->p_mlnk = p_MCB;
  156. /* Priority inversion, check which task continues. */
  157. if (os_tsk.run->prio >= rt_rdy_prio()) {
  158. rt_dispatch (p_TCB);
  159. }
  160. else {
  161. /* Ready task has higher priority than running task. */
  162. rt_put_prio (&os_rdy, os_tsk.run);
  163. rt_put_prio (&os_rdy, p_TCB);
  164. os_tsk.run->state = READY;
  165. p_TCB->state = READY;
  166. rt_dispatch (NULL);
  167. }
  168. }
  169. else {
  170. /* Check if own priority lowered by priority inversion. */
  171. if (rt_rdy_prio() > os_tsk.run->prio) {
  172. rt_put_prio (&os_rdy, os_tsk.run);
  173. os_tsk.run->state = READY;
  174. rt_dispatch (NULL);
  175. }
  176. }
  177. return (OS_R_OK);
  178. }
  179. /*--------------------------- rt_mut_wait -----------------------------------*/
  180. OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout) {
  181. /* Wait for a mutex, continue when mutex is free. */
  182. P_MUCB p_MCB = mutex;
  183. if (p_MCB->level == 0U) {
  184. p_MCB->owner = os_tsk.run;
  185. p_MCB->p_mlnk = os_tsk.run->p_mlnk;
  186. os_tsk.run->p_mlnk = p_MCB;
  187. p_MCB->level = 1U;
  188. return (OS_R_OK);
  189. }
  190. if (p_MCB->owner == os_tsk.run) {
  191. /* OK, running task is the owner of this mutex. */
  192. if (p_MCB->level == 0xFFFFU) {
  193. return (OS_R_NOK);
  194. }
  195. p_MCB->level++;
  196. return (OS_R_OK);
  197. }
  198. /* Mutex owned by another task, wait until released. */
  199. if (timeout == 0U) {
  200. return (OS_R_TMO);
  201. }
  202. /* Raise the owner task priority if lower than current priority. */
  203. /* This priority inversion is called priority inheritance. */
  204. if (p_MCB->owner->prio < os_tsk.run->prio) {
  205. p_MCB->owner->prio = os_tsk.run->prio;
  206. rt_resort_prio (p_MCB->owner);
  207. }
  208. if (p_MCB->p_lnk != NULL) {
  209. rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
  210. }
  211. else {
  212. p_MCB->p_lnk = os_tsk.run;
  213. os_tsk.run->p_lnk = NULL;
  214. os_tsk.run->p_rlnk = (P_TCB)p_MCB;
  215. }
  216. rt_block(timeout, WAIT_MUT);
  217. return (OS_R_TMO);
  218. }
  219. /*----------------------------------------------------------------------------
  220. * end of file
  221. *---------------------------------------------------------------------------*/