mirror of
https://github.com/silenty4ng/uv-k5-firmware-chinese-lts
synced 2025-01-30 14:14:31 +00:00
252 lines
6.7 KiB
C
252 lines
6.7 KiB
C
/*----------------------------------------------------------------------------
|
|
* 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
|
|
*---------------------------------------------------------------------------*/
|