uv-k5-firmware-chinese-lts/external/CMSIS_5/CMSIS/RTOS/RTX/SRC/rt_Mutex.c

253 lines
6.7 KiB
C
Raw Normal View History

2023-11-30 06:38:27 +00:00
/*----------------------------------------------------------------------------
* CMSIS-RTOS - RTX
*----------------------------------------------------------------------------
* Name: RT_MUTEX.C
* Purpose: Implements mutex synchronization objects
* Rev.: V4.82
*----------------------------------------------------------------------------
*
* Copyright (c) 1999-2009 KEIL, 2009-2017 ARM Germany GmbH. 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.
*---------------------------------------------------------------------------*/
#include "rt_TypeDef.h"
#include "RTX_Config.h"
#include "rt_List.h"
#include "rt_Task.h"
#include "rt_Mutex.h"
#include "rt_HAL_CM.h"
/*----------------------------------------------------------------------------
* Functions
*---------------------------------------------------------------------------*/
/*--------------------------- rt_mut_init -----------------------------------*/
void rt_mut_init (OS_ID mutex) {
/* Initialize a mutex object */
P_MUCB p_MCB = mutex;
p_MCB->cb_type = MUCB;
p_MCB->level = 0U;
p_MCB->p_lnk = NULL;
p_MCB->owner = NULL;
p_MCB->p_mlnk = NULL;
}
/*--------------------------- rt_mut_delete ---------------------------------*/
#ifdef __CMSIS_RTOS
OS_RESULT rt_mut_delete (OS_ID mutex) {
/* Delete a mutex object */
P_MUCB p_MCB = mutex;
P_TCB p_TCB;
P_MUCB p_mlnk;
U8 prio;
if (p_MCB->level != 0U) {
p_TCB = p_MCB->owner;
/* Remove mutex from task mutex owner list. */
p_mlnk = p_TCB->p_mlnk;
if (p_mlnk == p_MCB) {
p_TCB->p_mlnk = p_MCB->p_mlnk;
}
else {
while (p_mlnk) {
if (p_mlnk->p_mlnk == p_MCB) {
p_mlnk->p_mlnk = p_MCB->p_mlnk;
break;
}
p_mlnk = p_mlnk->p_mlnk;
}
}
/* Restore owner task's priority. */
prio = p_TCB->prio_base;
p_mlnk = p_TCB->p_mlnk;
while (p_mlnk) {
if ((p_mlnk->p_lnk != NULL) && (p_mlnk->p_lnk->prio > prio)) {
/* A task with higher priority is waiting for mutex. */
prio = p_mlnk->p_lnk->prio;
}
p_mlnk = p_mlnk->p_mlnk;
}
if (p_TCB->prio != prio) {
p_TCB->prio = prio;
if (p_TCB != os_tsk.run) {
rt_resort_prio (p_TCB);
}
}
}
while (p_MCB->p_lnk != NULL) {
/* A task is waiting for mutex. */
p_TCB = rt_get_first ((P_XCB)p_MCB);
rt_ret_val(p_TCB, 0U/*osOK*/);
rt_rmv_dly(p_TCB);
p_TCB->state = READY;
rt_put_prio (&os_rdy, p_TCB);
}
if ((os_rdy.p_lnk != NULL) && (os_rdy.p_lnk->prio > os_tsk.run->prio)) {
/* preempt running task */
rt_put_prio (&os_rdy, os_tsk.run);
os_tsk.run->state = READY;
rt_dispatch (NULL);
}
p_MCB->cb_type = 0U;
return (OS_R_OK);
}
#endif
/*--------------------------- rt_mut_release --------------------------------*/
OS_RESULT rt_mut_release (OS_ID mutex) {
/* Release a mutex object */
P_MUCB p_MCB = mutex;
P_TCB p_TCB;
P_MUCB p_mlnk;
U8 prio;
if ((p_MCB->level == 0U) || (p_MCB->owner != os_tsk.run)) {
/* Unbalanced mutex release or task is not the owner */
return (OS_R_NOK);
}
if (--p_MCB->level != 0U) {
return (OS_R_OK);
}
/* Remove mutex from task mutex owner list. */
p_mlnk = os_tsk.run->p_mlnk;
if (p_mlnk == p_MCB) {
os_tsk.run->p_mlnk = p_MCB->p_mlnk;
}
else {
while (p_mlnk) {
if (p_mlnk->p_mlnk == p_MCB) {
p_mlnk->p_mlnk = p_MCB->p_mlnk;
break;
}
p_mlnk = p_mlnk->p_mlnk;
}
}
/* Restore owner task's priority. */
prio = os_tsk.run->prio_base;
p_mlnk = os_tsk.run->p_mlnk;
while (p_mlnk) {
if ((p_mlnk->p_lnk != NULL) && (p_mlnk->p_lnk->prio > prio)) {
/* A task with higher priority is waiting for mutex. */
prio = p_mlnk->p_lnk->prio;
}
p_mlnk = p_mlnk->p_mlnk;
}
os_tsk.run->prio = prio;
if (p_MCB->p_lnk != NULL) {
/* A task is waiting for mutex. */
p_TCB = rt_get_first ((P_XCB)p_MCB);
#ifdef __CMSIS_RTOS
rt_ret_val(p_TCB, 0U/*osOK*/);
#else
rt_ret_val(p_TCB, OS_R_MUT);
#endif
rt_rmv_dly (p_TCB);
/* A waiting task becomes the owner of this mutex. */
p_MCB->level = 1U;
p_MCB->owner = p_TCB;
p_MCB->p_mlnk = p_TCB->p_mlnk;
p_TCB->p_mlnk = p_MCB;
/* Priority inversion, check which task continues. */
if (os_tsk.run->prio >= rt_rdy_prio()) {
rt_dispatch (p_TCB);
}
else {
/* Ready task has higher priority than running task. */
rt_put_prio (&os_rdy, os_tsk.run);
rt_put_prio (&os_rdy, p_TCB);
os_tsk.run->state = READY;
p_TCB->state = READY;
rt_dispatch (NULL);
}
}
else {
/* Check if own priority lowered by priority inversion. */
if (rt_rdy_prio() > os_tsk.run->prio) {
rt_put_prio (&os_rdy, os_tsk.run);
os_tsk.run->state = READY;
rt_dispatch (NULL);
}
}
return (OS_R_OK);
}
/*--------------------------- rt_mut_wait -----------------------------------*/
OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout) {
/* Wait for a mutex, continue when mutex is free. */
P_MUCB p_MCB = mutex;
if (p_MCB->level == 0U) {
p_MCB->owner = os_tsk.run;
p_MCB->p_mlnk = os_tsk.run->p_mlnk;
os_tsk.run->p_mlnk = p_MCB;
p_MCB->level = 1U;
return (OS_R_OK);
}
if (p_MCB->owner == os_tsk.run) {
/* OK, running task is the owner of this mutex. */
if (p_MCB->level == 0xFFFFU) {
return (OS_R_NOK);
}
p_MCB->level++;
return (OS_R_OK);
}
/* Mutex owned by another task, wait until released. */
if (timeout == 0U) {
return (OS_R_TMO);
}
/* Raise the owner task priority if lower than current priority. */
/* This priority inversion is called priority inheritance. */
if (p_MCB->owner->prio < os_tsk.run->prio) {
p_MCB->owner->prio = os_tsk.run->prio;
rt_resort_prio (p_MCB->owner);
}
if (p_MCB->p_lnk != NULL) {
rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
}
else {
p_MCB->p_lnk = os_tsk.run;
os_tsk.run->p_lnk = NULL;
os_tsk.run->p_rlnk = (P_TCB)p_MCB;
}
rt_block(timeout, WAIT_MUT);
return (OS_R_TMO);
}
/*----------------------------------------------------------------------------
* end of file
*---------------------------------------------------------------------------*/