rtx_mutex.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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_1(MutexGetName, const char *, osMutexId_t)
  60. SVC0_2(MutexAcquire, osStatus_t, osMutexId_t, uint32_t)
  61. SVC0_1(MutexRelease, osStatus_t, osMutexId_t)
  62. SVC0_1(MutexGetOwner, osThreadId_t, osMutexId_t)
  63. SVC0_1(MutexDelete, osStatus_t, osMutexId_t)
  64. /// Create and Initialize a Mutex object.
  65. /// \note API identical to osMutexNew
  66. osMutexId_t os_svcMutexNew (const osMutexAttr_t *attr) {
  67. os_mutex_t *mutex;
  68. uint32_t attr_bits;
  69. uint8_t flags;
  70. const char *name;
  71. // Process attributes
  72. if (attr != NULL) {
  73. name = attr->name;
  74. attr_bits = attr->attr_bits;
  75. mutex = attr->cb_mem;
  76. if (mutex != NULL) {
  77. if (((uint32_t)mutex & 3U) || (attr->cb_size < sizeof(os_mutex_t))) {
  78. return NULL;
  79. }
  80. } else {
  81. if (attr->cb_size != 0U) {
  82. return NULL;
  83. }
  84. }
  85. } else {
  86. name = NULL;
  87. attr_bits = 0U;
  88. mutex = NULL;
  89. }
  90. // Allocate object memory if not provided
  91. if (mutex == NULL) {
  92. if (os_Info.mpi.mutex != NULL) {
  93. mutex = os_MemoryPoolAlloc(os_Info.mpi.mutex);
  94. } else {
  95. mutex = os_MemoryAlloc(os_Info.mem.common, sizeof(os_mutex_t), 1U);
  96. }
  97. if (mutex == NULL) {
  98. return NULL;
  99. }
  100. flags = os_FlagSystemObject;
  101. } else {
  102. flags = 0U;
  103. }
  104. // Initialize control block
  105. mutex->id = os_IdMutex;
  106. mutex->state = os_ObjectActive;
  107. mutex->flags = flags;
  108. mutex->attr = (uint8_t)attr_bits;
  109. mutex->name = name;
  110. mutex->thread_list = NULL;
  111. mutex->owner_thread = NULL;
  112. mutex->owner_prev = NULL;
  113. mutex->owner_next = NULL;
  114. mutex->lock = 0U;
  115. return mutex;
  116. }
  117. /// Get name of a Mutex object.
  118. /// \note API identical to osMutexGetName
  119. const char *os_svcMutexGetName (osMutexId_t mutex_id) {
  120. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  121. // Check parameters
  122. if ((mutex == NULL) ||
  123. (mutex->id != os_IdMutex)) {
  124. return NULL;
  125. }
  126. // Check object state
  127. if (mutex->state == os_ObjectInactive) {
  128. return NULL;
  129. }
  130. return mutex->name;
  131. }
  132. /// Acquire a Mutex or timeout if it is locked.
  133. /// \note API identical to osMutexAcquire
  134. osStatus_t os_svcMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
  135. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  136. os_thread_t *runnig_thread;
  137. runnig_thread = os_ThreadGetRunning();
  138. if (runnig_thread == NULL) {
  139. return osError;
  140. }
  141. // Check parameters
  142. if ((mutex == NULL) ||
  143. (mutex->id != os_IdMutex)) {
  144. return osErrorParameter;
  145. }
  146. // Check object state
  147. if (mutex->state == os_ObjectInactive) {
  148. return osErrorResource;
  149. }
  150. // Check if Mutex is not locked
  151. if (mutex->lock == 0U) {
  152. // Acquire Mutex
  153. mutex->owner_thread = runnig_thread;
  154. mutex->owner_next = runnig_thread->mutex_list;
  155. mutex->owner_prev = NULL;
  156. runnig_thread->mutex_list = mutex;
  157. mutex->lock = 1U;
  158. return osOK;
  159. }
  160. // Check if Mutex is recursive and running Thread is the owner
  161. if ((mutex->attr & osMutexRecursive) && (mutex->owner_thread == runnig_thread)) {
  162. // Increment lock counter
  163. if (mutex->lock == os_MutexLockLimit) {
  164. return osErrorResource;
  165. }
  166. mutex->lock++;
  167. return osOK;
  168. }
  169. // Check if timeout is specified
  170. if (timeout != 0U) {
  171. // Check if Priority inheritance protocol is enabled
  172. if (mutex->attr & osMutexPrioInherit) {
  173. // Raise priority of owner Thread if lower than priority of running Thread
  174. if (mutex->owner_thread->priority < runnig_thread->priority) {
  175. mutex->owner_thread->priority = runnig_thread->priority;
  176. os_ThreadListSort(mutex->owner_thread);
  177. }
  178. }
  179. // Suspend current Thread
  180. os_ThreadListPut((os_object_t*)mutex, runnig_thread);
  181. os_ThreadWaitEnter(os_ThreadWaitingMutex, timeout);
  182. return osErrorTimeout;
  183. }
  184. // Mutex was not acquired
  185. return osErrorResource;
  186. }
  187. /// Release a Mutex that was acquired by osMutexAcquire.
  188. /// \note API identical to osMutexRelease
  189. osStatus_t os_svcMutexRelease (osMutexId_t mutex_id) {
  190. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  191. os_mutex_t *mutex0;
  192. os_thread_t *thread;
  193. os_thread_t *runnig_thread;
  194. int8_t priority;
  195. runnig_thread = os_ThreadGetRunning();
  196. if (runnig_thread == NULL) {
  197. return osError;
  198. }
  199. // Check parameters
  200. if ((mutex == NULL) ||
  201. (mutex->id != os_IdMutex)) {
  202. return osErrorParameter;
  203. }
  204. // Check object state
  205. if (mutex->state == os_ObjectInactive) {
  206. return osErrorResource;
  207. }
  208. // Check if Mutex is not locked or running Thread is not the owner
  209. if ((mutex->lock == 0U) || (mutex->owner_thread != runnig_thread)) {
  210. return osErrorResource;
  211. }
  212. // Decrement Lock counter
  213. if (--mutex->lock != 0U) {
  214. return osOK;
  215. }
  216. // Remove Mutex from Thread owner list
  217. if (mutex->owner_next != NULL) {
  218. mutex->owner_next->owner_prev = mutex->owner_prev;
  219. }
  220. if (mutex->owner_prev != NULL) {
  221. mutex->owner_prev->owner_next = mutex->owner_next;
  222. } else {
  223. runnig_thread->mutex_list = mutex->owner_next;
  224. }
  225. // Restore running Thread priority
  226. if (mutex->attr & osMutexPrioInherit) {
  227. priority = runnig_thread->priority_base;
  228. mutex0 = runnig_thread->mutex_list;
  229. while (mutex0) {
  230. // Mutexes owned by running Thread
  231. if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
  232. // Higher priority Thread is waiting for Mutex
  233. priority = mutex0->thread_list->priority;
  234. }
  235. mutex0 = mutex0->owner_next;
  236. }
  237. runnig_thread->priority = priority;
  238. }
  239. // Check if Thread is waiting for a Mutex
  240. if (mutex->thread_list != NULL) {
  241. // Wakeup waiting Thread with highest Priority
  242. thread = os_ThreadListGet((os_object_t*)mutex);
  243. os_ThreadWaitExit(thread, (uint32_t)osOK, false);
  244. // Thread is the new Mutex owner
  245. mutex->owner_thread = thread;
  246. mutex->owner_next = thread->mutex_list;
  247. mutex->owner_prev = NULL;
  248. thread->mutex_list = mutex;
  249. mutex->lock = 1U;
  250. }
  251. os_ThreadDispatch(NULL);
  252. return osOK;
  253. }
  254. /// Get Thread which owns a Mutex object.
  255. /// \note API identical to osMutexGetOwner
  256. osThreadId_t os_svcMutexGetOwner (osMutexId_t mutex_id) {
  257. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  258. // Check parameters
  259. if ((mutex == NULL) ||
  260. (mutex->id != os_IdMutex)) {
  261. return NULL;
  262. }
  263. // Check object state
  264. if (mutex->state == os_ObjectInactive) {
  265. return NULL;
  266. }
  267. // Check if Mutex is locked
  268. if (mutex->lock != 0U) {
  269. return mutex->owner_thread;
  270. }
  271. return NULL;
  272. }
  273. /// Delete a Mutex object.
  274. /// \note API identical to osMutexDelete
  275. osStatus_t os_svcMutexDelete (osMutexId_t mutex_id) {
  276. os_mutex_t *mutex = (os_mutex_t *)mutex_id;
  277. os_mutex_t *mutex0;
  278. os_thread_t *thread;
  279. int8_t priority;
  280. // Check parameters
  281. if ((mutex == NULL) ||
  282. (mutex->id != os_IdMutex)) {
  283. return osErrorParameter;
  284. }
  285. // Check object state
  286. if (mutex->state == os_ObjectInactive) {
  287. return osErrorResource;
  288. }
  289. // Mark object as inactive
  290. mutex->state = os_ObjectInactive;
  291. // Check if Mutex is locked
  292. if (mutex->lock != 0U) {
  293. thread = mutex->owner_thread;
  294. // Remove Mutex from Thread owner list
  295. if (mutex->owner_next != NULL) {
  296. mutex->owner_next->owner_prev = mutex->owner_prev;
  297. }
  298. if (mutex->owner_prev != NULL) {
  299. mutex->owner_prev->owner_next = mutex->owner_next;
  300. } else {
  301. thread->mutex_list = mutex->owner_next;
  302. }
  303. // Restore owner Thread priority
  304. if (mutex->attr & osMutexPrioInherit) {
  305. priority = thread->priority_base;
  306. mutex0 = thread->mutex_list;
  307. while (mutex0) {
  308. // Mutexes owned by running Thread
  309. if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
  310. // Higher priority Thread is waiting for Mutex
  311. priority = mutex0->thread_list->priority;
  312. }
  313. mutex0 = mutex0->owner_next;
  314. }
  315. if (thread->priority != priority) {
  316. thread->priority = priority;
  317. os_ThreadListSort(thread);
  318. }
  319. }
  320. // Unblock waiting threads
  321. if (mutex->thread_list != NULL) {
  322. do {
  323. thread = os_ThreadListGet((os_object_t*)mutex);
  324. os_ThreadWaitExit(thread, (uint32_t)osErrorResource, false);
  325. } while (mutex->thread_list != NULL);
  326. }
  327. os_ThreadDispatch(NULL);
  328. }
  329. // Free object memory
  330. if (mutex->flags & os_FlagSystemObject) {
  331. if (os_Info.mpi.mutex != NULL) {
  332. os_MemoryPoolFree(os_Info.mpi.mutex, mutex);
  333. } else {
  334. os_MemoryFree(os_Info.mem.common, mutex);
  335. }
  336. }
  337. return osOK;
  338. }
  339. // ==== Public API ====
  340. /// Create and Initialize a Mutex object.
  341. osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
  342. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  343. return NULL;
  344. }
  345. if ((os_KernelGetState() == os_KernelReady) && IS_PRIVILEGED()) {
  346. // Kernel Ready (not running) and in Privileged mode
  347. return os_svcMutexNew(attr);
  348. } else {
  349. return __svcMutexNew(attr);
  350. }
  351. }
  352. /// Get name of a Mutex object.
  353. const char *osMutexGetName (osMutexId_t mutex_id) {
  354. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  355. return NULL;
  356. }
  357. return __svcMutexGetName(mutex_id);
  358. }
  359. /// Acquire a Mutex or timeout if it is locked.
  360. osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
  361. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  362. return osErrorISR;
  363. }
  364. return __svcMutexAcquire(mutex_id, timeout);
  365. }
  366. /// Release a Mutex that was acquired by \ref osMutexAcquire.
  367. osStatus_t osMutexRelease (osMutexId_t mutex_id) {
  368. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  369. return osErrorISR;
  370. }
  371. return __svcMutexRelease(mutex_id);
  372. }
  373. /// Get Thread which owns a Mutex object.
  374. osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
  375. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  376. return NULL;
  377. }
  378. return __svcMutexGetOwner(mutex_id);
  379. }
  380. /// Delete a Mutex object.
  381. osStatus_t osMutexDelete (osMutexId_t mutex_id) {
  382. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  383. return osErrorISR;
  384. }
  385. return __svcMutexDelete(mutex_id);
  386. }