rtx_mutex.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * Copyright (c) 2013-2021 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. * 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. // OS Runtime Object Memory Usage
  27. #ifdef RTX_OBJ_MEM_USAGE
  28. osRtxObjectMemUsage_t osRtxMutexMemUsage \
  29. __attribute__((section(".data.os.mutex.obj"))) =
  30. { 0U, 0U, 0U };
  31. #endif
  32. // ==== Library functions ====
  33. /// Release Mutex list when owner Thread terminates.
  34. /// \param[in] mutex_list mutex list.
  35. void osRtxMutexOwnerRelease (os_mutex_t *mutex_list) {
  36. os_mutex_t *mutex;
  37. os_mutex_t *mutex_next;
  38. os_thread_t *thread;
  39. mutex = mutex_list;
  40. while (mutex != NULL) {
  41. mutex_next = mutex->owner_next;
  42. // Check if Mutex is Robust
  43. if ((mutex->attr & osMutexRobust) != 0U) {
  44. // Clear Lock counter
  45. mutex->lock = 0U;
  46. EvrRtxMutexReleased(mutex, 0U);
  47. // Check if Thread is waiting for a Mutex
  48. if (mutex->thread_list != NULL) {
  49. // Wakeup waiting Thread with highest Priority
  50. thread = osRtxThreadListGet(osRtxObject(mutex));
  51. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  52. // Thread is the new Mutex owner
  53. mutex->owner_thread = thread;
  54. mutex->owner_prev = NULL;
  55. mutex->owner_next = thread->mutex_list;
  56. if (thread->mutex_list != NULL) {
  57. thread->mutex_list->owner_prev = mutex;
  58. }
  59. thread->mutex_list = mutex;
  60. mutex->lock = 1U;
  61. EvrRtxMutexAcquired(mutex, 1U);
  62. }
  63. }
  64. mutex = mutex_next;
  65. }
  66. }
  67. /// Restore Mutex owner Thread priority.
  68. /// \param[in] mutex mutex object.
  69. /// \param[in] thread_wakeup thread wakeup object.
  70. void osRtxMutexOwnerRestore (const os_mutex_t *mutex, const os_thread_t *thread_wakeup) {
  71. const os_mutex_t *mutex0;
  72. os_thread_t *thread;
  73. const os_thread_t *thread0;
  74. int8_t priority;
  75. // Restore owner Thread priority
  76. if ((mutex->attr & osMutexPrioInherit) != 0U) {
  77. thread = mutex->owner_thread;
  78. priority = thread->priority_base;
  79. mutex0 = thread->mutex_list;
  80. // Check Mutexes owned by Thread
  81. do {
  82. if ((mutex0->attr & osMutexPrioInherit) != 0U) {
  83. // Check Threads waiting for Mutex
  84. thread0 = mutex0->thread_list;
  85. if (thread0 == thread_wakeup) {
  86. // Skip thread that is waken-up
  87. thread0 = thread0->thread_next;
  88. }
  89. if ((thread0 != NULL) && (thread0->priority > priority)) {
  90. // Higher priority Thread is waiting for Mutex
  91. priority = thread0->priority;
  92. }
  93. }
  94. mutex0 = mutex0->owner_next;
  95. } while (mutex0 != NULL);
  96. if (thread->priority != priority) {
  97. thread->priority = priority;
  98. osRtxThreadListSort(thread);
  99. }
  100. }
  101. }
  102. // ==== Service Calls ====
  103. /// Create and Initialize a Mutex object.
  104. /// \note API identical to osMutexNew
  105. static osMutexId_t svcRtxMutexNew (const osMutexAttr_t *attr) {
  106. os_mutex_t *mutex;
  107. uint32_t attr_bits;
  108. uint8_t flags;
  109. const char *name;
  110. // Process attributes
  111. if (attr != NULL) {
  112. name = attr->name;
  113. attr_bits = attr->attr_bits;
  114. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  115. mutex = attr->cb_mem;
  116. if (mutex != NULL) {
  117. //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
  118. if ((((uint32_t)mutex & 3U) != 0U) || (attr->cb_size < sizeof(os_mutex_t))) {
  119. EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
  120. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  121. return NULL;
  122. }
  123. } else {
  124. if (attr->cb_size != 0U) {
  125. EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
  126. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  127. return NULL;
  128. }
  129. }
  130. } else {
  131. name = NULL;
  132. attr_bits = 0U;
  133. mutex = NULL;
  134. }
  135. // Allocate object memory if not provided
  136. if (mutex == NULL) {
  137. if (osRtxInfo.mpi.mutex != NULL) {
  138. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  139. mutex = osRtxMemoryPoolAlloc(osRtxInfo.mpi.mutex);
  140. } else {
  141. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  142. mutex = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_mutex_t), 1U);
  143. }
  144. #ifdef RTX_OBJ_MEM_USAGE
  145. if (mutex != NULL) {
  146. uint32_t used;
  147. osRtxMutexMemUsage.cnt_alloc++;
  148. used = osRtxMutexMemUsage.cnt_alloc - osRtxMutexMemUsage.cnt_free;
  149. if (osRtxMutexMemUsage.max_used < used) {
  150. osRtxMutexMemUsage.max_used = used;
  151. }
  152. }
  153. #endif
  154. flags = osRtxFlagSystemObject;
  155. } else {
  156. flags = 0U;
  157. }
  158. if (mutex != NULL) {
  159. // Initialize control block
  160. mutex->id = osRtxIdMutex;
  161. mutex->flags = flags;
  162. mutex->attr = (uint8_t)attr_bits;
  163. mutex->name = name;
  164. mutex->thread_list = NULL;
  165. mutex->owner_thread = NULL;
  166. mutex->owner_prev = NULL;
  167. mutex->owner_next = NULL;
  168. mutex->lock = 0U;
  169. EvrRtxMutexCreated(mutex, mutex->name);
  170. } else {
  171. EvrRtxMutexError(NULL, (int32_t)osErrorNoMemory);
  172. }
  173. return mutex;
  174. }
  175. /// Get name of a Mutex object.
  176. /// \note API identical to osMutexGetName
  177. static const char *svcRtxMutexGetName (osMutexId_t mutex_id) {
  178. os_mutex_t *mutex = osRtxMutexId(mutex_id);
  179. // Check parameters
  180. if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
  181. EvrRtxMutexGetName(mutex, NULL);
  182. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  183. return NULL;
  184. }
  185. EvrRtxMutexGetName(mutex, mutex->name);
  186. return mutex->name;
  187. }
  188. /// Acquire a Mutex or timeout if it is locked.
  189. /// \note API identical to osMutexAcquire
  190. static osStatus_t svcRtxMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
  191. os_mutex_t *mutex = osRtxMutexId(mutex_id);
  192. os_thread_t *thread;
  193. osStatus_t status;
  194. // Check running thread
  195. thread = osRtxThreadGetRunning();
  196. if (thread == NULL) {
  197. EvrRtxMutexError(mutex, osRtxErrorKernelNotRunning);
  198. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  199. return osError;
  200. }
  201. // Check parameters
  202. if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
  203. EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
  204. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  205. return osErrorParameter;
  206. }
  207. // Check if Mutex is not locked
  208. if (mutex->lock == 0U) {
  209. // Acquire Mutex
  210. mutex->owner_thread = thread;
  211. mutex->owner_prev = NULL;
  212. mutex->owner_next = thread->mutex_list;
  213. if (thread->mutex_list != NULL) {
  214. thread->mutex_list->owner_prev = mutex;
  215. }
  216. thread->mutex_list = mutex;
  217. mutex->lock = 1U;
  218. EvrRtxMutexAcquired(mutex, mutex->lock);
  219. status = osOK;
  220. } else {
  221. // Check if Mutex is recursive and running Thread is the owner
  222. if (((mutex->attr & osMutexRecursive) != 0U) && (mutex->owner_thread == thread)) {
  223. // Try to increment lock counter
  224. if (mutex->lock == osRtxMutexLockLimit) {
  225. EvrRtxMutexError(mutex, osRtxErrorMutexLockLimit);
  226. status = osErrorResource;
  227. } else {
  228. mutex->lock++;
  229. EvrRtxMutexAcquired(mutex, mutex->lock);
  230. status = osOK;
  231. }
  232. } else {
  233. // Check if timeout is specified
  234. if (timeout != 0U) {
  235. // Check if Priority inheritance protocol is enabled
  236. if ((mutex->attr & osMutexPrioInherit) != 0U) {
  237. // Raise priority of owner Thread if lower than priority of running Thread
  238. if (mutex->owner_thread->priority < thread->priority) {
  239. mutex->owner_thread->priority = thread->priority;
  240. osRtxThreadListSort(mutex->owner_thread);
  241. }
  242. }
  243. EvrRtxMutexAcquirePending(mutex, timeout);
  244. // Suspend current Thread
  245. if (osRtxThreadWaitEnter(osRtxThreadWaitingMutex, timeout)) {
  246. osRtxThreadListPut(osRtxObject(mutex), thread);
  247. } else {
  248. EvrRtxMutexAcquireTimeout(mutex);
  249. }
  250. status = osErrorTimeout;
  251. } else {
  252. EvrRtxMutexNotAcquired(mutex);
  253. status = osErrorResource;
  254. }
  255. }
  256. }
  257. return status;
  258. }
  259. /// Release a Mutex that was acquired by osMutexAcquire.
  260. /// \note API identical to osMutexRelease
  261. static osStatus_t svcRtxMutexRelease (osMutexId_t mutex_id) {
  262. os_mutex_t *mutex = osRtxMutexId(mutex_id);
  263. const os_mutex_t *mutex0;
  264. os_thread_t *thread;
  265. int8_t priority;
  266. // Check running thread
  267. thread = osRtxThreadGetRunning();
  268. if (thread == NULL) {
  269. EvrRtxMutexError(mutex, osRtxErrorKernelNotRunning);
  270. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  271. return osError;
  272. }
  273. // Check parameters
  274. if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
  275. EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
  276. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  277. return osErrorParameter;
  278. }
  279. // Check if Mutex is not locked
  280. if (mutex->lock == 0U) {
  281. EvrRtxMutexError(mutex, osRtxErrorMutexNotLocked);
  282. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  283. return osErrorResource;
  284. }
  285. // Check if running Thread is not the owner
  286. if (mutex->owner_thread != thread) {
  287. EvrRtxMutexError(mutex, osRtxErrorMutexNotOwned);
  288. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  289. return osErrorResource;
  290. }
  291. // Decrement Lock counter
  292. mutex->lock--;
  293. EvrRtxMutexReleased(mutex, mutex->lock);
  294. // Check Lock counter
  295. if (mutex->lock == 0U) {
  296. // Remove Mutex from Thread owner list
  297. if (mutex->owner_next != NULL) {
  298. mutex->owner_next->owner_prev = mutex->owner_prev;
  299. }
  300. if (mutex->owner_prev != NULL) {
  301. mutex->owner_prev->owner_next = mutex->owner_next;
  302. } else {
  303. thread->mutex_list = mutex->owner_next;
  304. }
  305. // Restore running Thread priority
  306. priority = thread->priority_base;
  307. mutex0 = thread->mutex_list;
  308. // Check mutexes owned by running Thread
  309. while (mutex0 != NULL) {
  310. if ((mutex0->attr & osMutexPrioInherit) != 0U) {
  311. if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
  312. // Higher priority Thread is waiting for Mutex
  313. priority = mutex0->thread_list->priority;
  314. }
  315. }
  316. mutex0 = mutex0->owner_next;
  317. }
  318. thread->priority = priority;
  319. // Check if Thread is waiting for a Mutex
  320. if (mutex->thread_list != NULL) {
  321. // Wakeup waiting Thread with highest Priority
  322. thread = osRtxThreadListGet(osRtxObject(mutex));
  323. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  324. // Thread is the new Mutex owner
  325. mutex->owner_thread = thread;
  326. mutex->owner_prev = NULL;
  327. mutex->owner_next = thread->mutex_list;
  328. if (thread->mutex_list != NULL) {
  329. thread->mutex_list->owner_prev = mutex;
  330. }
  331. thread->mutex_list = mutex;
  332. mutex->lock = 1U;
  333. EvrRtxMutexAcquired(mutex, 1U);
  334. }
  335. osRtxThreadDispatch(NULL);
  336. }
  337. return osOK;
  338. }
  339. /// Get Thread which owns a Mutex object.
  340. /// \note API identical to osMutexGetOwner
  341. static osThreadId_t svcRtxMutexGetOwner (osMutexId_t mutex_id) {
  342. os_mutex_t *mutex = osRtxMutexId(mutex_id);
  343. // Check parameters
  344. if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
  345. EvrRtxMutexGetOwner(mutex, NULL);
  346. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  347. return NULL;
  348. }
  349. // Check if Mutex is not locked
  350. if (mutex->lock == 0U) {
  351. EvrRtxMutexGetOwner(mutex, NULL);
  352. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  353. return NULL;
  354. }
  355. EvrRtxMutexGetOwner(mutex, mutex->owner_thread);
  356. return mutex->owner_thread;
  357. }
  358. /// Delete a Mutex object.
  359. /// \note API identical to osMutexDelete
  360. static osStatus_t svcRtxMutexDelete (osMutexId_t mutex_id) {
  361. os_mutex_t *mutex = osRtxMutexId(mutex_id);
  362. const os_mutex_t *mutex0;
  363. os_thread_t *thread;
  364. int8_t priority;
  365. // Check parameters
  366. if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
  367. EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
  368. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  369. return osErrorParameter;
  370. }
  371. // Check if Mutex is locked
  372. if (mutex->lock != 0U) {
  373. thread = mutex->owner_thread;
  374. // Remove Mutex from Thread owner list
  375. if (mutex->owner_next != NULL) {
  376. mutex->owner_next->owner_prev = mutex->owner_prev;
  377. }
  378. if (mutex->owner_prev != NULL) {
  379. mutex->owner_prev->owner_next = mutex->owner_next;
  380. } else {
  381. thread->mutex_list = mutex->owner_next;
  382. }
  383. // Restore owner Thread priority
  384. priority = thread->priority_base;
  385. mutex0 = thread->mutex_list;
  386. // Check Mutexes owned by Thread
  387. while (mutex0 != NULL) {
  388. if ((mutex0->attr & osMutexPrioInherit) != 0U) {
  389. if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
  390. // Higher priority Thread is waiting for Mutex
  391. priority = mutex0->thread_list->priority;
  392. }
  393. }
  394. mutex0 = mutex0->owner_next;
  395. }
  396. if (thread->priority != priority) {
  397. thread->priority = priority;
  398. osRtxThreadListSort(thread);
  399. }
  400. // Unblock waiting threads
  401. while (mutex->thread_list != NULL) {
  402. thread = osRtxThreadListGet(osRtxObject(mutex));
  403. osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
  404. }
  405. osRtxThreadDispatch(NULL);
  406. }
  407. // Mark object as invalid
  408. mutex->id = osRtxIdInvalid;
  409. // Free object memory
  410. if ((mutex->flags & osRtxFlagSystemObject) != 0U) {
  411. if (osRtxInfo.mpi.mutex != NULL) {
  412. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
  413. } else {
  414. (void)osRtxMemoryFree(osRtxInfo.mem.common, mutex);
  415. }
  416. #ifdef RTX_OBJ_MEM_USAGE
  417. osRtxMutexMemUsage.cnt_free++;
  418. #endif
  419. }
  420. EvrRtxMutexDestroyed(mutex);
  421. return osOK;
  422. }
  423. // Service Calls definitions
  424. //lint ++flb "Library Begin" [MISRA Note 11]
  425. SVC0_1(MutexNew, osMutexId_t, const osMutexAttr_t *)
  426. SVC0_1(MutexGetName, const char *, osMutexId_t)
  427. SVC0_2(MutexAcquire, osStatus_t, osMutexId_t, uint32_t)
  428. SVC0_1(MutexRelease, osStatus_t, osMutexId_t)
  429. SVC0_1(MutexGetOwner, osThreadId_t, osMutexId_t)
  430. SVC0_1(MutexDelete, osStatus_t, osMutexId_t)
  431. //lint --flb "Library End"
  432. // ==== Public API ====
  433. /// Create and Initialize a Mutex object.
  434. osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
  435. osMutexId_t mutex_id;
  436. EvrRtxMutexNew(attr);
  437. if (IsException() || IsIrqMasked()) {
  438. EvrRtxMutexError(NULL, (int32_t)osErrorISR);
  439. mutex_id = NULL;
  440. } else {
  441. mutex_id = __svcMutexNew(attr);
  442. }
  443. return mutex_id;
  444. }
  445. /// Get name of a Mutex object.
  446. const char *osMutexGetName (osMutexId_t mutex_id) {
  447. const char *name;
  448. if (IsException() || IsIrqMasked()) {
  449. EvrRtxMutexGetName(mutex_id, NULL);
  450. name = NULL;
  451. } else {
  452. name = __svcMutexGetName(mutex_id);
  453. }
  454. return name;
  455. }
  456. /// Acquire a Mutex or timeout if it is locked.
  457. osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
  458. osStatus_t status;
  459. EvrRtxMutexAcquire(mutex_id, timeout);
  460. if (IsException() || IsIrqMasked()) {
  461. EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
  462. status = osErrorISR;
  463. } else {
  464. status = __svcMutexAcquire(mutex_id, timeout);
  465. }
  466. return status;
  467. }
  468. /// Release a Mutex that was acquired by \ref osMutexAcquire.
  469. osStatus_t osMutexRelease (osMutexId_t mutex_id) {
  470. osStatus_t status;
  471. EvrRtxMutexRelease(mutex_id);
  472. if (IsException() || IsIrqMasked()) {
  473. EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
  474. status = osErrorISR;
  475. } else {
  476. status = __svcMutexRelease(mutex_id);
  477. }
  478. return status;
  479. }
  480. /// Get Thread which owns a Mutex object.
  481. osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
  482. osThreadId_t thread;
  483. if (IsException() || IsIrqMasked()) {
  484. EvrRtxMutexGetOwner(mutex_id, NULL);
  485. thread = NULL;
  486. } else {
  487. thread = __svcMutexGetOwner(mutex_id);
  488. }
  489. return thread;
  490. }
  491. /// Delete a Mutex object.
  492. osStatus_t osMutexDelete (osMutexId_t mutex_id) {
  493. osStatus_t status;
  494. EvrRtxMutexDelete(mutex_id);
  495. if (IsException() || IsIrqMasked()) {
  496. EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
  497. status = osErrorISR;
  498. } else {
  499. status = __svcMutexDelete(mutex_id);
  500. }
  501. return status;
  502. }