uv-k5-firmware-chinese-lts/external/CMSIS_5/CMSIS/RTOS2/RTX/Source/rtx_mutex.c
2023-11-30 14:38:27 +08:00

702 lines
21 KiB
C

/*
* Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: Mutex functions
*
* -----------------------------------------------------------------------------
*/
#include "rtx_lib.h"
// OS Runtime Object Memory Usage
#ifdef RTX_OBJ_MEM_USAGE
osRtxObjectMemUsage_t osRtxMutexMemUsage \
__attribute__((section(".data.os.mutex.obj"))) =
{ 0U, 0U, 0U };
#endif
// ==== Helper functions ====
/// Verify that Mutex object pointer is valid.
/// \param[in] mutex mutex object.
/// \return true - valid, false - invalid.
static bool_t IsMutexPtrValid (const os_mutex_t *mutex) {
#ifdef RTX_OBJ_PTR_CHECK
//lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
uint32_t cb_start = (uint32_t)&__os_mutex_cb_start__;
uint32_t cb_length = (uint32_t)&__os_mutex_cb_length__;
// Check the section boundaries
if (((uint32_t)mutex - cb_start) >= cb_length) {
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return FALSE;
}
// Check the object alignment
if ((((uint32_t)mutex - cb_start) % sizeof(os_mutex_t)) != 0U) {
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return FALSE;
}
#else
// Check NULL pointer
if (mutex == NULL) {
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return FALSE;
}
#endif
return TRUE;
}
// ==== Library functions ====
/// Release Mutex list when owner Thread terminates.
/// \param[in] mutex_list mutex list.
void osRtxMutexOwnerRelease (os_mutex_t *mutex_list) {
os_mutex_t *mutex;
os_mutex_t *mutex_next;
os_thread_t *thread;
mutex = mutex_list;
while (mutex != NULL) {
mutex_next = mutex->owner_next;
// Check if Mutex is Robust
if ((mutex->attr & osMutexRobust) != 0U) {
// Clear Lock counter
mutex->lock = 0U;
EvrRtxMutexReleased(mutex, 0U);
// Check if Thread is waiting for a Mutex
if (mutex->thread_list != NULL) {
// Wakeup waiting Thread with highest Priority
thread = osRtxThreadListGet(osRtxObject(mutex));
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
// Thread is the new Mutex owner
mutex->owner_thread = thread;
mutex->owner_prev = NULL;
mutex->owner_next = thread->mutex_list;
if (thread->mutex_list != NULL) {
thread->mutex_list->owner_prev = mutex;
}
thread->mutex_list = mutex;
mutex->lock = 1U;
EvrRtxMutexAcquired(mutex, 1U);
}
}
mutex = mutex_next;
}
}
/// Restore Mutex owner Thread priority.
/// \param[in] mutex mutex object.
/// \param[in] thread_wakeup thread wakeup object.
void osRtxMutexOwnerRestore (const os_mutex_t *mutex, const os_thread_t *thread_wakeup) {
const os_mutex_t *mutex0;
os_thread_t *thread;
const os_thread_t *thread0;
int8_t priority;
// Restore owner Thread priority
if ((mutex->attr & osMutexPrioInherit) != 0U) {
thread = mutex->owner_thread;
priority = thread->priority_base;
mutex0 = thread->mutex_list;
// Check Mutexes owned by Thread
do {
if ((mutex0->attr & osMutexPrioInherit) != 0U) {
// Check Threads waiting for Mutex
thread0 = mutex0->thread_list;
if (thread0 == thread_wakeup) {
// Skip thread that is waken-up
thread0 = thread0->thread_next;
}
if ((thread0 != NULL) && (thread0->priority > priority)) {
// Higher priority Thread is waiting for Mutex
priority = thread0->priority;
}
}
mutex0 = mutex0->owner_next;
} while (mutex0 != NULL);
if (thread->priority != priority) {
thread->priority = priority;
osRtxThreadListSort(thread);
}
}
}
/// Unlock Mutex owner when mutex is deleted.
/// \param[in] mutex mutex object.
/// \return true - successful, false - not locked.
static bool_t osRtxMutexOwnerUnlock (os_mutex_t *mutex) {
const os_mutex_t *mutex0;
os_thread_t *thread;
int8_t priority;
// Check if Mutex is locked
if (mutex->lock == 0U) {
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return FALSE;
}
thread = mutex->owner_thread;
// Remove Mutex from Thread owner list
if (mutex->owner_next != NULL) {
mutex->owner_next->owner_prev = mutex->owner_prev;
}
if (mutex->owner_prev != NULL) {
mutex->owner_prev->owner_next = mutex->owner_next;
} else {
thread->mutex_list = mutex->owner_next;
}
// Restore owner Thread priority
priority = thread->priority_base;
mutex0 = thread->mutex_list;
// Check Mutexes owned by Thread
while (mutex0 != NULL) {
if ((mutex0->attr & osMutexPrioInherit) != 0U) {
if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
// Higher priority Thread is waiting for Mutex
priority = mutex0->thread_list->priority;
}
}
mutex0 = mutex0->owner_next;
}
if (thread->priority != priority) {
thread->priority = priority;
osRtxThreadListSort(thread);
}
// Unblock waiting threads
while (mutex->thread_list != NULL) {
thread = osRtxThreadListGet(osRtxObject(mutex));
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
}
mutex->lock = 0U;
return TRUE;
}
/// Destroy a Mutex object.
/// \param[in] mutex mutex object.
static void osRtxMutexDestroy (os_mutex_t *mutex) {
// Mark object as invalid
mutex->id = osRtxIdInvalid;
// Free object memory
if ((mutex->flags & osRtxFlagSystemObject) != 0U) {
#ifdef RTX_OBJ_PTR_CHECK
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
#else
if (osRtxInfo.mpi.mutex != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, mutex);
}
#endif
#ifdef RTX_OBJ_MEM_USAGE
osRtxMutexMemUsage.cnt_free++;
#endif
}
EvrRtxMutexDestroyed(mutex);
}
#ifdef RTX_SAFETY_CLASS
/// Delete a Mutex safety class.
/// \param[in] safety_class safety class.
/// \param[in] mode safety mode.
void osRtxMutexDeleteClass (uint32_t safety_class, uint32_t mode) {
os_mutex_t *mutex;
uint32_t length;
//lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
mutex = (os_mutex_t *)(uint32_t)&__os_mutex_cb_start__;
length = (uint32_t)&__os_mutex_cb_length__;
while (length >= sizeof(os_mutex_t)) {
if ( (mutex->id == osRtxIdMutex) &&
((((mode & osSafetyWithSameClass) != 0U) &&
((mutex->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
(((mode & osSafetyWithLowerClass) != 0U) &&
((mutex->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
(void)osRtxMutexOwnerUnlock(mutex);
osRtxMutexDestroy(mutex);
}
length -= sizeof(os_mutex_t);
mutex++;
}
}
#endif
// ==== Service Calls ====
/// Create and Initialize a Mutex object.
/// \note API identical to osMutexNew
static osMutexId_t svcRtxMutexNew (const osMutexAttr_t *attr) {
os_mutex_t *mutex;
#ifdef RTX_SAFETY_CLASS
const os_thread_t *thread = osRtxThreadGetRunning();
#endif
uint32_t attr_bits;
uint8_t flags;
const char *name;
// Process attributes
if (attr != NULL) {
name = attr->name;
attr_bits = attr->attr_bits;
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
mutex = attr->cb_mem;
#ifdef RTX_SAFETY_CLASS
if ((attr_bits & osSafetyClass_Valid) != 0U) {
if ((thread != NULL) &&
((thread->attr >> osRtxAttrClass_Pos) <
(uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
EvrRtxMutexError(NULL, (int32_t)osErrorSafetyClass);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
}
#endif
if (mutex != NULL) {
if (!IsMutexPtrValid(mutex) || (attr->cb_size != sizeof(os_mutex_t))) {
EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
} else {
if (attr->cb_size != 0U) {
EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
}
} else {
name = NULL;
attr_bits = 0U;
mutex = NULL;
}
// Allocate object memory if not provided
if (mutex == NULL) {
if (osRtxInfo.mpi.mutex != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mutex = osRtxMemoryPoolAlloc(osRtxInfo.mpi.mutex);
#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mutex = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_mutex_t), 1U);
#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (mutex != NULL) {
uint32_t used;
osRtxMutexMemUsage.cnt_alloc++;
used = osRtxMutexMemUsage.cnt_alloc - osRtxMutexMemUsage.cnt_free;
if (osRtxMutexMemUsage.max_used < used) {
osRtxMutexMemUsage.max_used = used;
}
}
#endif
flags = osRtxFlagSystemObject;
} else {
flags = 0U;
}
if (mutex != NULL) {
// Initialize control block
mutex->id = osRtxIdMutex;
mutex->flags = flags;
mutex->attr = (uint8_t)(attr_bits & ~osRtxAttrClass_Msk);
mutex->name = name;
mutex->thread_list = NULL;
mutex->owner_thread = NULL;
mutex->owner_prev = NULL;
mutex->owner_next = NULL;
mutex->lock = 0U;
#ifdef RTX_SAFETY_CLASS
if ((attr_bits & osSafetyClass_Valid) != 0U) {
mutex->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
(osSafetyClass_Pos - osRtxAttrClass_Pos));
} else {
// Inherit safety class from the running thread
if (thread != NULL) {
mutex->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
}
}
#endif
EvrRtxMutexCreated(mutex, mutex->name);
} else {
EvrRtxMutexError(NULL, (int32_t)osErrorNoMemory);
}
return mutex;
}
/// Get name of a Mutex object.
/// \note API identical to osMutexGetName
static const char *svcRtxMutexGetName (osMutexId_t mutex_id) {
os_mutex_t *mutex = osRtxMutexId(mutex_id);
// Check parameters
if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexGetName(mutex, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
EvrRtxMutexGetName(mutex, mutex->name);
return mutex->name;
}
/// Acquire a Mutex or timeout if it is locked.
/// \note API identical to osMutexAcquire
static osStatus_t svcRtxMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
os_mutex_t *mutex = osRtxMutexId(mutex_id);
os_thread_t *thread;
osStatus_t status;
// Check running thread
thread = osRtxThreadGetRunning();
if (thread == NULL) {
EvrRtxMutexError(mutex, osRtxErrorKernelNotRunning);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osError;
}
// Check parameters
if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
#ifdef RTX_SAFETY_CLASS
// Check running thread safety class
if ((thread->attr >> osRtxAttrClass_Pos) < (mutex->attr >> osRtxAttrClass_Pos)) {
EvrRtxMutexError(mutex, (int32_t)osErrorSafetyClass);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorSafetyClass;
}
#endif
// Check if Mutex is not locked
if (mutex->lock == 0U) {
// Acquire Mutex
mutex->owner_thread = thread;
mutex->owner_prev = NULL;
mutex->owner_next = thread->mutex_list;
if (thread->mutex_list != NULL) {
thread->mutex_list->owner_prev = mutex;
}
thread->mutex_list = mutex;
mutex->lock = 1U;
EvrRtxMutexAcquired(mutex, mutex->lock);
status = osOK;
} else {
// Check if Mutex is recursive and running Thread is the owner
if (((mutex->attr & osMutexRecursive) != 0U) && (mutex->owner_thread == thread)) {
// Try to increment lock counter
if (mutex->lock == osRtxMutexLockLimit) {
EvrRtxMutexError(mutex, osRtxErrorMutexLockLimit);
status = osErrorResource;
} else {
mutex->lock++;
EvrRtxMutexAcquired(mutex, mutex->lock);
status = osOK;
}
} else {
// Check if timeout is specified
if (timeout != 0U) {
// Check if Priority inheritance protocol is enabled
if ((mutex->attr & osMutexPrioInherit) != 0U) {
// Raise priority of owner Thread if lower than priority of running Thread
if (mutex->owner_thread->priority < thread->priority) {
mutex->owner_thread->priority = thread->priority;
osRtxThreadListSort(mutex->owner_thread);
}
}
EvrRtxMutexAcquirePending(mutex, timeout);
// Suspend current Thread
if (osRtxThreadWaitEnter(osRtxThreadWaitingMutex, timeout)) {
osRtxThreadListPut(osRtxObject(mutex), thread);
} else {
EvrRtxMutexAcquireTimeout(mutex);
}
status = osErrorTimeout;
} else {
EvrRtxMutexNotAcquired(mutex);
status = osErrorResource;
}
}
}
return status;
}
/// Release a Mutex that was acquired by osMutexAcquire.
/// \note API identical to osMutexRelease
static osStatus_t svcRtxMutexRelease (osMutexId_t mutex_id) {
os_mutex_t *mutex = osRtxMutexId(mutex_id);
const os_mutex_t *mutex0;
os_thread_t *thread;
int8_t priority;
// Check running thread
thread = osRtxThreadGetRunning();
if (thread == NULL) {
EvrRtxMutexError(mutex, osRtxErrorKernelNotRunning);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osError;
}
// Check parameters
if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
// Check if Mutex is not locked
if (mutex->lock == 0U) {
EvrRtxMutexError(mutex, osRtxErrorMutexNotLocked);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorResource;
}
// Check if running Thread is not the owner
if (mutex->owner_thread != thread) {
EvrRtxMutexError(mutex, osRtxErrorMutexNotOwned);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorResource;
}
// Decrement Lock counter
mutex->lock--;
EvrRtxMutexReleased(mutex, mutex->lock);
// Check Lock counter
if (mutex->lock == 0U) {
// Remove Mutex from Thread owner list
if (mutex->owner_next != NULL) {
mutex->owner_next->owner_prev = mutex->owner_prev;
}
if (mutex->owner_prev != NULL) {
mutex->owner_prev->owner_next = mutex->owner_next;
} else {
thread->mutex_list = mutex->owner_next;
}
// Restore running Thread priority
priority = thread->priority_base;
mutex0 = thread->mutex_list;
// Check mutexes owned by running Thread
while (mutex0 != NULL) {
if ((mutex0->attr & osMutexPrioInherit) != 0U) {
if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
// Higher priority Thread is waiting for Mutex
priority = mutex0->thread_list->priority;
}
}
mutex0 = mutex0->owner_next;
}
thread->priority = priority;
// Check if Thread is waiting for a Mutex
if (mutex->thread_list != NULL) {
// Wakeup waiting Thread with highest Priority
thread = osRtxThreadListGet(osRtxObject(mutex));
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
// Thread is the new Mutex owner
mutex->owner_thread = thread;
mutex->owner_prev = NULL;
mutex->owner_next = thread->mutex_list;
if (thread->mutex_list != NULL) {
thread->mutex_list->owner_prev = mutex;
}
thread->mutex_list = mutex;
mutex->lock = 1U;
EvrRtxMutexAcquired(mutex, 1U);
}
osRtxThreadDispatch(NULL);
}
return osOK;
}
/// Get Thread which owns a Mutex object.
/// \note API identical to osMutexGetOwner
static osThreadId_t svcRtxMutexGetOwner (osMutexId_t mutex_id) {
os_mutex_t *mutex = osRtxMutexId(mutex_id);
// Check parameters
if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexGetOwner(mutex, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
// Check if Mutex is not locked
if (mutex->lock == 0U) {
EvrRtxMutexGetOwner(mutex, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
EvrRtxMutexGetOwner(mutex, mutex->owner_thread);
return mutex->owner_thread;
}
/// Delete a Mutex object.
/// \note API identical to osMutexDelete
static osStatus_t svcRtxMutexDelete (osMutexId_t mutex_id) {
os_mutex_t *mutex = osRtxMutexId(mutex_id);
#ifdef RTX_SAFETY_CLASS
const os_thread_t *thread;
#endif
// Check parameters
if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
#ifdef RTX_SAFETY_CLASS
// Check running thread safety class
thread = osRtxThreadGetRunning();
if ((thread != NULL) &&
((thread->attr >> osRtxAttrClass_Pos) < (mutex->attr >> osRtxAttrClass_Pos))) {
EvrRtxMutexError(mutex, (int32_t)osErrorSafetyClass);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorSafetyClass;
}
#endif
// Unlock the mutex owner
if (osRtxMutexOwnerUnlock(mutex)) {
osRtxThreadDispatch(NULL);
}
osRtxMutexDestroy(mutex);
return osOK;
}
// Service Calls definitions
//lint ++flb "Library Begin" [MISRA Note 11]
SVC0_1(MutexNew, osMutexId_t, const osMutexAttr_t *)
SVC0_1(MutexGetName, const char *, osMutexId_t)
SVC0_2(MutexAcquire, osStatus_t, osMutexId_t, uint32_t)
SVC0_1(MutexRelease, osStatus_t, osMutexId_t)
SVC0_1(MutexGetOwner, osThreadId_t, osMutexId_t)
SVC0_1(MutexDelete, osStatus_t, osMutexId_t)
//lint --flb "Library End"
// ==== Public API ====
/// Create and Initialize a Mutex object.
osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
osMutexId_t mutex_id;
EvrRtxMutexNew(attr);
if (IsException() || IsIrqMasked()) {
EvrRtxMutexError(NULL, (int32_t)osErrorISR);
mutex_id = NULL;
} else {
mutex_id = __svcMutexNew(attr);
}
return mutex_id;
}
/// Get name of a Mutex object.
const char *osMutexGetName (osMutexId_t mutex_id) {
const char *name;
if (IsException() || IsIrqMasked()) {
name = svcRtxMutexGetName(mutex_id);
} else {
name = __svcMutexGetName(mutex_id);
}
return name;
}
/// Acquire a Mutex or timeout if it is locked.
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
osStatus_t status;
EvrRtxMutexAcquire(mutex_id, timeout);
if (IsException() || IsIrqMasked()) {
EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
status = osErrorISR;
} else {
status = __svcMutexAcquire(mutex_id, timeout);
}
return status;
}
/// Release a Mutex that was acquired by \ref osMutexAcquire.
osStatus_t osMutexRelease (osMutexId_t mutex_id) {
osStatus_t status;
EvrRtxMutexRelease(mutex_id);
if (IsException() || IsIrqMasked()) {
EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
status = osErrorISR;
} else {
status = __svcMutexRelease(mutex_id);
}
return status;
}
/// Get Thread which owns a Mutex object.
osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
osThreadId_t thread;
if (IsException() || IsIrqMasked()) {
EvrRtxMutexGetOwner(mutex_id, NULL);
thread = NULL;
} else {
thread = __svcMutexGetOwner(mutex_id);
}
return thread;
}
/// Delete a Mutex object.
osStatus_t osMutexDelete (osMutexId_t mutex_id) {
osStatus_t status;
EvrRtxMutexDelete(mutex_id);
if (IsException() || IsIrqMasked()) {
EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
status = osErrorISR;
} else {
status = __svcMutexDelete(mutex_id);
}
return status;
}