rtx_mutex.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. * Copyright (c) 2013-2016 ARM Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * -----------------------------------------------------------------------------
  19. *
  20. * Project: CMSIS-RTOS RTX
  21. * Title: Mutex functions
  22. *
  23. * -----------------------------------------------------------------------------
  24. */
  25. #include "rtx_lib.h"
  26. // ==== Library functions ====
  27. /// Release Mutex list when owner Thread terminates.
  28. /// \param[in] mutex mutex object.
  29. /// \return 1 - success, 0 - failure.
  30. void os_MutexOwnerRelease (os_mutex_t *mutex_list) {
  31. os_mutex_t *mutex;
  32. os_thread_t *thread;
  33. mutex = mutex_list;
  34. while (mutex) {
  35. mutex_list = mutex->owner_next;
  36. // Check if Mutex is Robust
  37. if (mutex->attr & osMutexRobust) {
  38. // Clear Lock counter
  39. mutex->lock = 0U;
  40. // Check if Thread is waiting for a Mutex
  41. if (mutex->thread_list != NULL) {
  42. // Wakeup waiting Thread with highest Priority
  43. thread = os_ThreadListGet((os_object_t*)mutex);
  44. os_ThreadWaitExit(thread, (uint32_t)osOK, false);
  45. // Thread is the new Mutex owner
  46. mutex->owner_thread = thread;
  47. mutex->owner_next = thread->mutex_list;
  48. mutex->owner_prev = NULL;
  49. thread->mutex_list = mutex;
  50. mutex->lock = 1U;
  51. }
  52. }
  53. mutex = mutex_list;
  54. }
  55. }
  56. // ==== Service Calls ====
  57. // Service Calls definitions
  58. SVC0_1(MutexNew, osMutexId_t, const osMutexAttr_t *)
  59. SVC0_2(MutexAcquire, osStatus_t, osMutexId_t, uint32_t)
  60. SVC0_1(MutexRelease, osStatus_t, osMutexId_t)
  61. SVC0_1(MutexGetOwner, osThreadId_t, osMutexId_t)
  62. SVC0_1(MutexDelete, osStatus_t, osMutexId_t)
  63. /// Create and Initialize a Mutex object.
  64. /// \note API identical to osMutexNew
  65. osMutexId_t os_svcMutexNew (const osMutexAttr_t *attr) {
  66. os_mutex_t *mutex;
  67. uint32_t attr_bits;
  68. uint8_t flags;
  69. const char *name;
  70. // Process attributes
  71. if (attr != NULL) {
  72. name = attr->name;
  73. attr_bits = attr->attr_bits;
  74. mutex = attr->cb_mem;
  75. if (mutex != NULL) {
  76. if (((uint32_t)mutex & 3U) || (attr->cb_size < sizeof(os_mutex_t))) {
  77. return (osMutexId_t)NULL;
  78. }
  79. } else {
  80. if (attr->cb_size != 0U) {
  81. return (osMutexId_t)NULL;
  82. }
  83. }
  84. } else {
  85. name = NULL;
  86. attr_bits = 0U;
  87. mutex = NULL;
  88. }
  89. // Allocate object memory if not provided
  90. if (mutex == NULL) {
  91. if (os_Info.mpi.mutex != NULL) {
  92. mutex = os_MemoryPoolAlloc(os_Info.mpi.mutex);
  93. } else {
  94. mutex = os_MemoryAlloc(os_Info.mem.cb, sizeof(os_mutex_t));
  95. }
  96. if (mutex == NULL) {
  97. return (osMutexId_t)NULL;
  98. }
  99. flags = os_FlagSystemObject;
  100. } else {
  101. flags = 0U;
  102. }
  103. // Initialize control block
  104. mutex->id = os_IdMutex;
  105. mutex->state = os_ObjectActive;
  106. mutex->flags = flags;
  107. mutex->attr = (uint8_t)attr_bits;
  108. mutex->name = name;
  109. mutex->thread_list = NULL;
  110. mutex->owner_thread = NULL;
  111. mutex->owner_prev = NULL;
  112. mutex->owner_next = NULL;
  113. mutex->lock = 0U;
  114. return (osMutexId_t)mutex;
  115. }
  116. /// Acquire a Mutex or timeout if it is locked.
  117. /// \note API identical to osMutexAcquire
  118. osStatus_t os_svcMutexAcquire (osMutexId_t mutex_id, uint32_t millisec) {
  119. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  120. os_thread_t *runnig_thread;
  121. runnig_thread = os_ThreadGetRunning();
  122. if (runnig_thread == NULL) {
  123. return osError;
  124. }
  125. // Check parameters
  126. if ((mutex == NULL) ||
  127. (mutex->id != os_IdMutex)) {
  128. return osErrorParameter;
  129. }
  130. // Check object state
  131. if (mutex->state == os_ObjectInactive) {
  132. return osErrorResource;
  133. }
  134. // Check if Mutex is not locked
  135. if (mutex->lock == 0U) {
  136. // Acquire Mutex
  137. mutex->owner_thread = runnig_thread;
  138. mutex->owner_next = runnig_thread->mutex_list;
  139. mutex->owner_prev = NULL;
  140. runnig_thread->mutex_list = mutex;
  141. mutex->lock = 1U;
  142. return osOK;
  143. }
  144. // Check if Mutex is recursive and running Thread is the owner
  145. if ((mutex->attr & osMutexRecursive) && (mutex->owner_thread == runnig_thread)) {
  146. // Increment lock counter
  147. if (mutex->lock == os_MutexLockLimit) {
  148. return osErrorResource;
  149. }
  150. mutex->lock++;
  151. return osOK;
  152. }
  153. // Check if timeout is specified
  154. if (millisec != 0U) {
  155. // Check if Priority inheritance protocol is enabled
  156. if (mutex->attr & osMutexPrioInherit) {
  157. // Raise priority of owner Thread if lower than priority of running Thread
  158. if (mutex->owner_thread->priority < runnig_thread->priority) {
  159. mutex->owner_thread->priority = runnig_thread->priority;
  160. os_ThreadListSort(mutex->owner_thread);
  161. }
  162. }
  163. // Suspend current Thread
  164. os_ThreadListPut((os_object_t*)mutex, runnig_thread);
  165. os_ThreadWaitEnter(os_ThreadWaitingMutex, millisec);
  166. return osErrorTimeout;
  167. }
  168. // Mutex was not acquired
  169. return osErrorResource;
  170. }
  171. /// Release a Mutex that was acquired by osMutexAcquire.
  172. /// \note API identical to osMutexRelease
  173. osStatus_t os_svcMutexRelease (osMutexId_t mutex_id) {
  174. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  175. os_mutex_t *mutex0;
  176. os_thread_t *thread;
  177. os_thread_t *runnig_thread;
  178. int8_t priority;
  179. runnig_thread = os_ThreadGetRunning();
  180. if (runnig_thread == NULL) {
  181. return osError;
  182. }
  183. // Check parameters
  184. if ((mutex == NULL) ||
  185. (mutex->id != os_IdMutex)) {
  186. return osErrorParameter;
  187. }
  188. // Check object state
  189. if (mutex->state == os_ObjectInactive) {
  190. return osErrorResource;
  191. }
  192. // Check if Mutex is not locked or running Thread is not the owner
  193. if ((mutex->lock == 0U) || (mutex->owner_thread != runnig_thread)) {
  194. return osErrorResource;
  195. }
  196. // Decrement Lock counter
  197. if (--mutex->lock != 0U) {
  198. return osOK;
  199. }
  200. // Remove Mutex from Thread owner list
  201. if (mutex->owner_next != NULL) {
  202. mutex->owner_next->owner_prev = mutex->owner_prev;
  203. }
  204. if (mutex->owner_prev != NULL) {
  205. mutex->owner_prev->owner_next = mutex->owner_next;
  206. } else {
  207. runnig_thread->mutex_list = mutex->owner_next;
  208. }
  209. // Restore running Thread priority
  210. if (mutex->attr & osMutexPrioInherit) {
  211. priority = runnig_thread->priority_base;
  212. mutex0 = runnig_thread->mutex_list;
  213. while (mutex0) {
  214. // Mutexes owned by running Thread
  215. if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
  216. // Higher priority Thread is waiting for Mutex
  217. priority = mutex0->thread_list->priority;
  218. }
  219. mutex0 = mutex0->owner_next;
  220. }
  221. runnig_thread->priority = priority;
  222. }
  223. // Check if Thread is waiting for a Mutex
  224. if (mutex->thread_list != NULL) {
  225. // Wakeup waiting Thread with highest Priority
  226. thread = os_ThreadListGet((os_object_t*)mutex);
  227. os_ThreadWaitExit(thread, (uint32_t)osOK, false);
  228. // Thread is the new Mutex owner
  229. mutex->owner_thread = thread;
  230. mutex->owner_next = thread->mutex_list;
  231. mutex->owner_prev = NULL;
  232. thread->mutex_list = mutex;
  233. mutex->lock = 1U;
  234. }
  235. os_ThreadDispatch(NULL);
  236. return osOK;
  237. }
  238. /// Get Thread which owns a Mutex object.
  239. /// \note API identical to osMutexGetOwner
  240. osThreadId_t os_svcMutexGetOwner (osMutexId_t mutex_id) {
  241. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  242. // Check parameters
  243. if ((mutex == NULL) ||
  244. (mutex->id != os_IdMutex)) {
  245. return (osThreadId_t)NULL;
  246. }
  247. // Check object state
  248. if (mutex->state == os_ObjectInactive) {
  249. return (osThreadId_t)NULL;
  250. }
  251. // Check if Mutex is locked
  252. if (mutex->lock != 0U) {
  253. return (osThreadId_t)mutex->owner_thread;
  254. }
  255. return (osThreadId_t)NULL;
  256. }
  257. /// Delete a Mutex object.
  258. /// \note API identical to osMutexDelete
  259. osStatus_t os_svcMutexDelete (osMutexId_t mutex_id) {
  260. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  261. os_mutex_t *mutex0;
  262. os_thread_t *thread;
  263. int8_t priority;
  264. // Check parameters
  265. if ((mutex == NULL) ||
  266. (mutex->id != os_IdMutex)) {
  267. return osErrorParameter;
  268. }
  269. // Check object state
  270. if (mutex->state == os_ObjectInactive) {
  271. return osErrorResource;
  272. }
  273. // Mark object as inactive
  274. mutex->state = os_ObjectInactive;
  275. // Check if Mutex is locked
  276. if (mutex->lock != 0U) {
  277. thread = mutex->owner_thread;
  278. // Remove Mutex from Thread owner list
  279. if (mutex->owner_next != NULL) {
  280. mutex->owner_next->owner_prev = mutex->owner_prev;
  281. }
  282. if (mutex->owner_prev != NULL) {
  283. mutex->owner_prev->owner_next = mutex->owner_next;
  284. } else {
  285. thread->mutex_list = mutex->owner_next;
  286. }
  287. // Restore owner Thread priority
  288. if (mutex->attr & osMutexPrioInherit) {
  289. priority = thread->priority_base;
  290. mutex0 = thread->mutex_list;
  291. while (mutex0) {
  292. // Mutexes owned by running Thread
  293. if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
  294. // Higher priority Thread is waiting for Mutex
  295. priority = mutex0->thread_list->priority;
  296. }
  297. mutex0 = mutex0->owner_next;
  298. }
  299. if (thread->priority != priority) {
  300. thread->priority = priority;
  301. os_ThreadListSort(thread);
  302. }
  303. }
  304. // Unblock waiting threads
  305. if (mutex->thread_list != NULL) {
  306. do {
  307. thread = os_ThreadListGet((os_object_t*)mutex);
  308. os_ThreadWaitExit(thread, (uint32_t)osErrorResource, false);
  309. } while (mutex->thread_list != NULL);
  310. }
  311. os_ThreadDispatch(NULL);
  312. }
  313. // Free object memory
  314. if (mutex->flags & os_FlagSystemObject) {
  315. if (os_Info.mpi.mutex != NULL) {
  316. os_MemoryPoolFree(os_Info.mpi.mutex, mutex);
  317. } else {
  318. os_MemoryFree(os_Info.mem.cb, mutex);
  319. }
  320. }
  321. return osOK;
  322. }
  323. // ==== Public API ====
  324. /// Create and Initialize a Mutex object.
  325. osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
  326. if (__get_IPSR() != 0U) {
  327. return (osMutexId_t)NULL; // Not allowed in ISR
  328. }
  329. if ((os_KernelGetState() == os_KernelReady) && ((__get_CONTROL() & 1U) == 0U)) {
  330. // Kernel Ready (not running) and in Privileged mode
  331. return os_svcMutexNew(attr);
  332. } else {
  333. return __svcMutexNew(attr);
  334. }
  335. }
  336. /// Acquire a Mutex or timeout if it is locked.
  337. osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t millisec) {
  338. if (__get_IPSR() != 0U) {
  339. return osErrorISR; // Not allowed in ISR
  340. }
  341. return __svcMutexAcquire(mutex_id, millisec);
  342. }
  343. /// Release a Mutex that was acquired by \ref osMutexAcquire.
  344. osStatus_t osMutexRelease (osMutexId_t mutex_id) {
  345. if (__get_IPSR() != 0U) {
  346. return osErrorISR; // Not allowed in ISR
  347. }
  348. return __svcMutexRelease(mutex_id);
  349. }
  350. /// Get Thread which owns a Mutex object.
  351. osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
  352. if (__get_IPSR() != 0U) {
  353. return (osThreadId_t)NULL; // Not allowed in ISR
  354. }
  355. return __svcMutexGetOwner(mutex_id);
  356. }
  357. /// Delete a Mutex object.
  358. osStatus_t osMutexDelete (osMutexId_t mutex_id) {
  359. if (__get_IPSR() != 0U) {
  360. return osErrorISR; // Not allowed in ISR
  361. }
  362. return __svcMutexDelete(mutex_id);
  363. }