//作用:管理互斥量的代码
/*
*********************************************************************************************************
* uC/OS-III
* The Real-Time Kernel
*
* Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 互斥锁管理
*
* 文件 : os_mutex.c
* 版本 : V3.08.02
*********************************************************************************************************
*/
#define MICRIUM_SOURCE
#include "os.h"
#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
const CPU_CHAR *os_mutex__c = "$Id: $";
#endif
#if (OS_CFG_MUTEX_EN > 0u)
/*
************************************************************************************************************************
* 创建互斥锁
*
* 描述: 此函数用于创建一个互斥锁。
*
* 参数: p_mutex 指向要初始化的互斥锁的指针。您的应用程序负责为互斥锁分配存储空间。
*
* p_name 指向您希望给互斥锁命名的指针。
*
* p_err 指向一个变量,该变量将包含此函数返回的错误代码。
*
* OS_ERR_NONE 如果调用成功
* OS_ERR_CREATE_ISR 如果您从中断服务例程 (ISR) 中调用了此函数
* OS_ERR_ILLEGAL_CREATE_RUN_TIME 如果您在调用 OSSafetyCriticalStart() 之后尝试创建互斥锁
* OS_ERR_OBJ_PTR_NULL 如果 'p_mutex' 是空指针
* OS_ERR_OBJ_CREATED 如果互斥锁已经创建
*
* 返回值: 无
*
* 注意: 无
************************************************************************************************************************
*/
void OSMutexCreate(OS_MUTEX *p_mutex, CPU_CHAR *p_name, OS_ERR *p_err)
{
CPU_SR_ALLOC(); // 分配 CPU 状态寄存器
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) { // 检查错误指针是否为空
OS_SAFETY_CRITICAL_EXCEPTION(); // 安全关键异常处理
return;
}
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == OS_TRUE) { // 检查是否在运行时创建互斥锁
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; // 运行时创建互斥锁非法
return;
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 检查是否从中断服务例程 (ISR) 调用
*p_err = OS_ERR_CREATE_ISR; // 从中断服务例程 (ISR) 创建互斥锁非法
return;
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mutex == (OS_MUTEX *)0) { // 检查互斥锁指针是否为空
*p_err = OS_ERR_OBJ_PTR_NULL; // 互斥锁指针为空
return;
}
#endif
CPU_CRITICAL_ENTER(); // 进入临界区
#if (OS_OBJ_TYPE_REQ > 0u)
#if (OS_CFG_OBJ_CREATED_CHK_EN > 0u)
if (p_mutex->Type == OS_OBJ_TYPE_MUTEX) { // 检查互斥锁是否已创建
CPU_CRITICAL_EXIT(); // 退出临界区
*p_err = OS_ERR_OBJ_CREATED; // 互斥锁已创建
return;
}
#endif
p_mutex->Type = OS_OBJ_TYPE_MUTEX; // 标记数据结构为互斥锁
#endif
#if (OS_CFG_DBG_EN > 0u)
p_mutex->NamePtr = p_name; // 设置互斥锁名称
#else
(void)p_name; // 忽略名称参数
#endif
p_mutex->MutexGrpNextPtr = (OS_MUTEX *)0; // 初始化互斥锁链表指针
p_mutex->OwnerTCBPtr = (OS_TCB *)0; // 初始化所有者任务控制块指针
p_mutex->OwnerNestingCtr = 0u; // 初始化嵌套计数器,表示互斥锁可用
#if (OS_CFG_TS_EN > 0u)
p_mutex->TS = 0u; // 初始化时间戳
#endif
OS_PendListInit(&p_mutex->PendList); // 初始化等待列表
#if (OS_CFG_DBG_EN > 0u)
OS_MutexDbgListAdd(p_mutex); // 将互斥锁添加到调试列表
OSMutexQty++; // 增加互斥锁数量
#endif
OS_TRACE_MUTEX_CREATE(p_mutex, p_name); // 跟踪互斥锁创建
CPU_CRITICAL_EXIT(); // 退出临界区
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
}
/*
************************************************************************************************************************
* 删除互斥锁
*
* 描述: 此函数删除一个互斥锁,并准备好所有在该互斥锁上等待的任务。
*
* 参数: p_mutex 指向要删除的互斥锁的指针
*
* opt 确定删除选项,如下所示:
*
* OS_OPT_DEL_NO_PEND 仅在没有任务等待时删除互斥锁
* OS_OPT_DEL_ALWAYS 即使有任务等待也删除互斥锁。
* 在这种情况下,所有等待的任务都将被准备好。
*
* p_err 指向一个变量,该变量将包含此函数返回的错误代码。
*
* OS_ERR_NONE 调用成功且互斥锁已被删除
* OS_ERR_DEL_ISR 如果您尝试从中断服务例程 (ISR) 中删除互斥锁
* OS_ERR_ILLEGAL_DEL_RUN_TIME 如果您在调用 OSStart() 之后尝试删除互斥锁
* OS_ERR_OBJ_PTR_NULL 如果 'p_mutex' 是空指针
* OS_ERR_OBJ_TYPE 如果 'p_mutex' 不是指向互斥锁的指针
* OS_ERR_OPT_INVALID 指定了无效的选项
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
* OS_ERR_TASK_WAITING 有一个或多个任务正在等待互斥锁
*
* 返回值: == 0 如果没有任务在等待互斥锁,或者发生错误。
* > 0 如果一个或多个等待互斥锁的任务现在已被准备好并通知。
*
* 注意: 1) 使用此函数时必须小心。通常期望互斥锁存在的任务必须检查 OSMutexPend() 的返回代码。
*
* 2) 因为所有在互斥锁上等待的任务都将被准备好,所以在互斥锁用于互斥的应用程序中,您必须小心,因为资源将不再受互斥锁保护。
************************************************************************************************************************
*/
#if (OS_CFG_MUTEX_DEL_EN > 0u)
OS_OBJ_QTY OSMutexDel(OS_MUTEX *p_mutex, OS_OPT opt, OS_ERR *p_err)
{
OS_OBJ_QTY nbr_tasks;
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
OS_TCB *p_tcb_owner;
CPU_TS ts;
#if (OS_CFG_MUTEX_EN > 0u)
OS_PRIO prio_new;
#endif
CPU_SR_ALLOC(); // 分配 CPU 状态寄存器
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) { // 检查错误指针是否为空
OS_SAFETY_CRITICAL_EXCEPTION(); // 安全关键异常处理
return (0u);
}
#endif
OS_TRACE_MUTEX_DEL_ENTER(p_mutex, opt); // 跟踪互斥锁删除进入
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == OS_TRUE) { // 检查是否在运行时删除互斥锁
OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME); // 跟踪互斥锁删除退出
*p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; // 运行时删除互斥锁非法
return (0u);
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 检查是否从中断服务例程 (ISR) 调用
OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_DEL_ISR); // 跟踪互斥锁删除退出
*p_err = OS_ERR_DEL_ISR; // 从中断服务例程 (ISR) 删除互斥锁非法
return (0u);
}
#endif
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 检查内核是否正在运行
OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OS_NOT_RUNNING); // 跟踪互斥锁删除退出
*p_err = OS_ERR_OS_NOT_RUNNING; // 内核尚未运行
return (0u);
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mutex == (OS_MUTEX *)0) { // 检查互斥锁指针是否为空
OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OBJ_PTR_NULL); // 跟踪互斥锁删除退出
*p_err = OS_ERR_OBJ_PTR_NULL; // 互斥锁指针为空
return (0u);
}
#endif
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { // 检查互斥锁是否已创建
OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OBJ_TYPE); // 跟踪互斥锁删除退出
*p_err = OS_ERR_OBJ_TYPE; // 互斥锁类型不匹配
return (0u);
}
#endif
CPU_CRITICAL_ENTER(); // 进入临界区
p_pend_list = &p_mutex->PendList;
nbr_tasks = 0u;
switch (opt) {
case OS_OPT_DEL_NO_PEND: // 仅在没有任务等待时删除互斥锁
if (p_pend_list->HeadPtr == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN > 0u)
OS_MutexDbgListRemove(p_mutex); // 从调试列表中移除互斥锁
OSMutexQty--; // 减少互斥锁数量
#endif
OS_TRACE_MUTEX_DEL(p_mutex); // 跟踪互斥锁删除
if (p_mutex->OwnerTCBPtr != (OS_TCB *)0) { // 检查互斥锁是否属于某个任务
OS_MutexGrpRemove(p_mutex->OwnerTCBPtr, p_mutex); // 从任务组中移除互斥锁
}
OS_MutexClr(p_mutex); // 清除互斥锁
CPU_CRITICAL_EXIT(); // 退出临界区
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
} else {
CPU_CRITICAL_EXIT(); // 退出临界区
*p_err = OS_ERR_TASK_WAITING; // 有任务在等待互斥锁
}
break;
case OS_OPT_DEL_ALWAYS: // 总是删除互斥锁
#if (OS_CFG_TS_EN > 0u)
ts = OS_TS_GET(); // 获取时间戳
#else
ts = 0u;
#endif
while (p_pend_list->HeadPtr != (OS_TCB *)0) { // 从等待列表中移除所有任务
p_tcb = p_pend_list->HeadPtr;
OS_PendAbort(p_tcb, ts, OS_STATUS_PEND_DEL); // 中止任务的等待
nbr_tasks++; // 增加已准备好的任务数量
}
#if (OS_CFG_DBG_EN > 0u)
OS_MutexDbgListRemove(p_mutex); // 从调试列表中移除互斥锁
OSMutexQty--; // 减少互斥锁数量
#endif
OS_TRACE_MUTEX_DEL(p_mutex); // 跟踪互斥锁删除
p_tcb_owner = p_mutex->OwnerTCBPtr;
if (p_tcb_owner != (OS_TCB *)0) { // 检查互斥锁是否属于某个任务
OS_MutexGrpRemove(p_tcb_owner, p_mutex); // 从任务组中移除互斥锁
}
if (p_tcb_owner != (OS_TCB *)0) { // 检查是否需要更改任务的优先级
if (p_tcb_owner->Prio != p_tcb_owner->BasePrio) {
prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner); // 查找任务组中的最高优先级
prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
OS_TaskChangePrio(p_tcb_owner, prio_new); // 更改任务的优先级
OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio); // 跟踪任务优先级继承解除
}
}
OS_MutexClr(p_mutex); // 清除互斥锁
CPU_CRITICAL_EXIT(); // 退出临界区
OSSched(); // 找到最高优先级的就绪任务
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
break;
default:
CPU_CRITICAL_EXIT(); // 退出临界区
*p_err = OS_ERR_OPT_INVALID; // 指定了无效的选项
break;
}
OS_TRACE_MUTEX_DEL_EXIT(*p_err); // 跟踪互斥锁删除退出
return (nbr_tasks); // 返回已准备好的任务数量
}
#endif
/*
************************************************************************************************************************
* 等待互斥锁
*
* 描述: 此函数等待一个互斥锁。
*
* 参数: p_mutex 指向互斥锁的指针
*
* timeout 是一个可选的超时周期(以时钟滴答为单位)。如果非零,您的任务将等待资源,最多等待由该参数指定的时间(以“滴答”为单位)。如果您指定 0,则您的任务将在指定的互斥锁上无限期等待,直到资源可用。
*
* opt 确定用户是否希望在互斥锁可用时阻塞:
*
* OS_OPT_PEND_BLOCKING
* OS_OPT_PEND_NON_BLOCKING
*
* p_ts 是一个指向变量的指针,该变量将接收互斥锁被发布、等待被中止或互斥锁被删除的时间戳。如果您传递一个空指针(即 (CPU_TS *)0),则不会获取时间戳。换句话说,传递空指针是有效的,表示您不需要时间戳。
*
* p_err 是一个指向变量的指针,该变量将包含此函数返回的错误代码。
*
* OS_ERR_NONE 调用成功且您的任务拥有资源
* OS_ERR_MUTEX_OWNER 如果调用任务已经拥有互斥锁
* OS_ERR_MUTEX_OVF 互斥锁嵌套计数器溢出
* OS_ERR_OBJ_DEL 如果 'p_mutex' 被删除
* OS_ERR_OBJ_PTR_NULL 如果 'p_mutex' 是空指针
* OS_ERR_OBJ_TYPE 如果 'p_mutex' 不是指向互斥锁的指针
* OS_ERR_OPT_INVALID 如果未指定有效的选项
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
* OS_ERR_PEND_ABORT 如果等待被其他任务中止
* OS_ERR_PEND_ISR 如果您从中断服务例程 (ISR) 调用此函数并且结果会导致挂起
* OS_ERR_PEND_WOULD_BLOCK 如果您指定了非阻塞但互斥锁不可用
* OS_ERR_SCHED_LOCKED 如果您在调度器锁定时调用此函数
* OS_ERR_STATUS_INVALID 如果等待状态具有无效值
* OS_ERR_TIMEOUT 互斥锁在指定的超时时间内未收到
* OS_ERR_TICK_DISABLED 如果内核滴答被禁用且指定了超时时间
*
* 返回值: 无
*
* 注意: 此 API “不得” 从定时器回调函数中调用。
************************************************************************************************************************
*/
void OSMutexPend(OS_MUTEX *p_mutex,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err)
{
OS_TCB *p_tcb;
CPU_SR_ALLOC();
#if (OS_CFG_TS_EN == 0u)
(void)p_ts; // 防止编译器警告未使用 'ts'
#endif
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
OS_TRACE_MUTEX_PEND_ENTER(p_mutex, timeout, opt, p_ts);
#if (OS_CFG_TICK_EN == 0u)
if (timeout != 0u) {
*p_err = OS_ERR_TICK_DISABLED;
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_TICK_DISABLED);
return;
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 不允许从中断服务例程 (ISR) 调用
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_ISR);
*p_err = OS_ERR_PEND_ISR;
return;
}
#endif
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 内核是否正在运行?
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OS_NOT_RUNNING);
*p_err = OS_ERR_OS_NOT_RUNNING;
return;
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mutex == (OS_MUTEX *)0) { // 验证参数
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OBJ_PTR_NULL);
*p_err = OS_ERR_OBJ_PTR_NULL;
return;
}
switch (opt) { // 验证 'opt'
case OS_OPT_PEND_BLOCKING:
case OS_OPT_PEND_NON_BLOCKING:
break;
default:
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OPT_INVALID);
*p_err = OS_ERR_OPT_INVALID;
return;
}
#endif
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { // 确保互斥锁已创建
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OBJ_TYPE);
*p_err = OS_ERR_OBJ_TYPE;
return;
}
#endif
CPU_CRITICAL_ENTER();
if (p_mutex->OwnerNestingCtr == 0u) { // 资源是否可用?
p_mutex->OwnerTCBPtr = OSTCBCurPtr; // 是,调用者可以继续
p_mutex->OwnerNestingCtr = 1u;
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = p_mutex->TS;
}
#endif
OS_MutexGrpAdd(OSTCBCurPtr, p_mutex); // 将互斥锁添加到所有者的组中
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_PEND(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_NONE);
*p_err = OS_ERR_NONE;
return;
}
if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) { // 当前任务是否已经是互斥锁的所有者?
if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)-1) {
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_MUTEX_OVF);
*p_err = OS_ERR_MUTEX_OVF;
return;
}
p_mutex->OwnerNestingCtr++;
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = p_mutex->TS;
}
#endif
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_MUTEX_OWNER);
*p_err = OS_ERR_MUTEX_OWNER; // 表示当前任务已经拥有互斥锁
return;
}
if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { // 调用者是否希望在不可用时阻塞?
CPU_CRITICAL_EXIT();
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = 0u;
}
#endif
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK);
*p_err = OS_ERR_PEND_WOULD_BLOCK; // 否
return;
} else {
if (OSSchedLockNestingCtr > 0u) { // 调度器锁定时不能等待
CPU_CRITICAL_EXIT();
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = 0u;
}
#endif
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_SCHED_LOCKED);
*p_err = OS_ERR_SCHED_LOCKED;
return;
}
}
p_tcb = p_mutex->OwnerTCBPtr; // 指向互斥锁所有者的 TCB
if (p_tcb->Prio > OSTCBCurPtr->Prio) { // 查看互斥锁所有者是否比当前任务优先级低
OS_TaskChangePrio(p_tcb, OSTCBCurPtr->Prio);
OS_TRACE_MUTEX_TASK_PRIO_INHERIT(p_tcb, p_tcb->Prio);
}
OS_Pend((OS_PEND_OBJ *)((void *)p_mutex), // 任务在互斥锁上等待
OSTCBCurPtr,
OS_TASK_PEND_ON_MUTEX,
timeout);
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_PEND_BLOCK(p_mutex);
OSSched(); // 找到下一个最高优先级的任务准备运行
CPU_CRITICAL_ENTER();
switch (OSTCBCurPtr->PendStatus) {
case OS_STATUS_PEND_OK: // 获取了互斥锁
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
#endif
OS_TRACE_MUTEX_PEND(p_mutex);
*p_err = OS_ERR_NONE;
break;
case OS_STATUS_PEND_ABORT: // 表示已中止
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
#endif
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
*p_err = OS_ERR_PEND_ABORT;
break;
case OS_STATUS_PEND_TIMEOUT: // 表示在超时时间内未获取互斥锁
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = 0u;
}
#endif
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
*p_err = OS_ERR_TIMEOUT;
break;
case OS_STATUS_PEND_DEL: // 表示等待的对象已被删除
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
#endif
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
*p_err = OS_ERR_OBJ_DEL;
break;
default:
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
*p_err = OS_ERR_STATUS_INVALID;
break;
}
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_PEND_EXIT(*p_err);
}
/*
************************************************************************************************************************
* 中止对互斥锁的等待
*
* 描述: 此函数中止并准备好当前正在等待互斥锁的任务。此函数应用于故障中止对互斥锁的等待,而不是通过 OSMutexPost() 正常信号互斥锁。
*
* 参数:
* p_mutex - 指向互斥锁的指针
*
* opt - 确定执行的中止类型:
*
* OS_OPT_PEND_ABORT_1 - 中止单个任务(最高优先级任务)对互斥锁的等待
* OS_OPT_PEND_ABORT_ALL - 中止所有等待互斥锁的任务
* OS_OPT_POST_NO_SCHED - 不调用调度器
*
* p_err - 指向一个变量的指针,该变量将包含此函数返回的错误代码。
*
* OS_ERR_NONE - 至少有一个等待互斥锁的任务被准备好并被告知等待已中止;检查返回值以获取等待互斥锁的任务数量
* OS_ERR_OBJ_PTR_NULL - 如果 'p_mutex' 是空指针
* OS_ERR_OBJ_TYPE - 如果 'p_mutex' 不是指向互斥锁的指针
* OS_ERR_OPT_INVALID - 如果指定了无效的选项
* OS_ERR_OS_NOT_RUNNING - 如果 uC/OS-III 尚未运行
* OS_ERR_PEND_ABORT_ISR - 如果尝试从中断服务例程 (ISR) 调用此函数
* OS_ERR_PEND_ABORT_NONE - 没有任务在等待
*
* 返回值:
* == 0 - 如果没有任务在等待互斥锁,或者发生错误。
* > 0 - 如果一个或多个等待互斥锁的任务现在已被准备好并被告知。
*
* 注意:
* 无
************************************************************************************************************************
*/
#if (OS_CFG_MUTEX_PEND_ABORT_EN > 0u)
OS_OBJ_QTY OSMutexPendAbort (OS_MUTEX *p_mutex,
OS_OPT opt,
OS_ERR *p_err)
{
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
OS_TCB *p_tcb_owner;
CPU_TS ts;
OS_OBJ_QTY nbr_tasks;
OS_PRIO prio_new;
CPU_SR_ALLOC();
// 安全关键检查
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_OBJ_QTY)0u);
}
#endif
// 检查是否从中断服务例程 (ISR) 调用
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 不允许从中断服务例程 (ISR) 中调用 Pend Abort
*p_err = OS_ERR_PEND_ABORT_ISR;
return (0u);
}
#endif
// 检查内核是否正在运行
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 内核是否正在运行?
*p_err = OS_ERR_OS_NOT_RUNNING;
return (0u);
}
#endif
// 参数检查
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mutex == (OS_MUTEX *)0) { // 验证 'p_mutex'
*p_err = OS_ERR_OBJ_PTR_NULL;
return (0u);
}
switch (opt) { // 验证 'opt'
case OS_OPT_PEND_ABORT_1:
case OS_OPT_PEND_ABORT_ALL:
case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED:
case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
break;
default:
*p_err = OS_ERR_OPT_INVALID;
return (0u);
}
#endif
// 对象类型检查
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { // 确保互斥锁已创建
*p_err = OS_ERR_OBJ_TYPE;
return (0u);
}
#endif
// 进入临界区
CPU_CRITICAL_ENTER();
p_pend_list = &p_mutex->PendList;
if (p_pend_list->HeadPtr == (OS_TCB *)0) { // 有任何任务在等待互斥锁吗?
CPU_CRITICAL_EXIT(); // 没有
*p_err = OS_ERR_PEND_ABORT_NONE;
return (0u);
}
nbr_tasks = 0u;
#if (OS_CFG_TS_EN > 0u)
ts = OS_TS_GET(); // 获取本地时间戳,以便所有任务获得相同的时间
#else
ts = 0u;
#endif
// 处理等待互斥锁的任务
while (p_pend_list->HeadPtr != (OS_TCB *)0) {
p_tcb = p_pend_list->HeadPtr;
OS_PendAbort(p_tcb,
ts,
OS_STATUS_PEND_ABORT);
p_tcb_owner = p_mutex->OwnerTCBPtr;
prio_new = p_tcb_owner->Prio;
if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) &&
(p_tcb_owner->Prio == p_tcb->Prio)) { // 拥有者是否继承了优先级?
prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
}
if(prio_new != p_tcb_owner->Prio) {
OS_TaskChangePrio(p_tcb_owner, prio_new);
OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio);
}
nbr_tasks++;
if (opt != OS_OPT_PEND_ABORT_ALL) { // 是否中止所有等待的任务?
break; // 否
}
}
CPU_CRITICAL_EXIT();
// 调用调度器
if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
OSSched(); // 运行调度器
}
*p_err = OS_ERR_NONE;
return (nbr_tasks);
}
#endif
/*
************************************************************************************************************************
* 信号量互斥锁
*
* 描述: 此函数用于信号互斥锁。
*
* 参数:
* p_mutex - 指向互斥锁的指针
*
* opt - 可以指定的选项,以改变信号的行为。选择包括:
*
* OS_OPT_POST_NONE - 没有特殊选项被选中
* OS_OPT_POST_NO_SCHED - 如果不希望在信号后调用调度器
*
* p_err - 指向一个变量的指针,该变量将包含此函数返回的错误代码。
*
* OS_ERR_NONE - 调用成功,互斥锁已被信号
* OS_ERR_MUTEX_NESTING - 互斥锁的所有者嵌套使用了互斥锁
* OS_ERR_MUTEX_NOT_OWNER - 发送信号的任务不是互斥锁的所有者
* OS_ERR_OBJ_PTR_NULL - 如果 'p_mutex' 是空指针
* OS_ERR_OBJ_TYPE - 如果 'p_mutex' 不是指向互斥锁的指针
* OS_ERR_OPT_INVALID - 如果指定了无效的选项
* OS_ERR_OS_NOT_RUNNING - 如果 uC/OS-III 尚未运行
* OS_ERR_POST_ISR - 如果尝试从中断服务例程 (ISR) 发送信号
*
* 返回值:
* 无
*
* 注意:
* 无
************************************************************************************************************************
*/
void OSMutexPost (OS_MUTEX *p_mutex,
OS_OPT opt,
OS_ERR *p_err)
{
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
CPU_TS ts;
OS_PRIO prio_new;
CPU_SR_ALLOC();
// 安全关键检查
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
// 追踪信号互斥锁进入
OS_TRACE_MUTEX_POST_ENTER(p_mutex, opt);
// 检查是否从中断服务例程 (ISR) 调用
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 不允许从中断服务例程 (ISR) 调用
OS_TRACE_MUTEX_POST_FAILED(p_mutex);
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_POST_ISR);
*p_err = OS_ERR_POST_ISR;
return;
}
#endif
// 检查内核是否正在运行
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 内核是否正在运行?
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
*p_err = OS_ERR_OS_NOT_RUNNING;
return;
}
#endif
// 参数检查
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_mutex == (OS_MUTEX *)0) { // 验证 'p_mutex'
OS_TRACE_MUTEX_POST_FAILED(p_mutex);
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
*p_err = OS_ERR_OBJ_PTR_NULL;
return;
}
switch (opt) { // 验证 'opt'
case OS_OPT_POST_NONE:
case OS_OPT_POST_NO_SCHED:
break;
default:
OS_TRACE_MUTEX_POST_FAILED(p_mutex);
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OPT_INVALID);
*p_err = OS_ERR_OPT_INVALID;
return;
}
#endif
// 对象类型检查
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { // 确保互斥锁已创建
OS_TRACE_MUTEX_POST_FAILED(p_mutex);
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OBJ_TYPE);
*p_err = OS_ERR_OBJ_TYPE;
return;
}
#endif
// 进入临界区
CPU_CRITICAL_ENTER();
if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) { // 确保互斥锁的所有者正在释放互斥锁
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_POST_FAILED(p_mutex);
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_MUTEX_NOT_OWNER);
*p_err = OS_ERR_MUTEX_NOT_OWNER;
return;
}
// 追踪信号互斥锁
OS_TRACE_MUTEX_POST(p_mutex);
// 获取时间戳
#if (OS_CFG_TS_EN > 0u)
ts = OS_TS_GET(); // 获取时间戳
p_mutex->TS = ts;
#else
ts = 0u;
#endif
p_mutex->OwnerNestingCtr--; // 减少所有者的嵌套计数
if (p_mutex->OwnerNestingCtr > 0u) { // 是否已完成所有嵌套?
CPU_CRITICAL_EXIT(); // 否
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_MUTEX_NESTING);
*p_err = OS_ERR_MUTEX_NESTING;
return;
}
// 从所有者的组中移除互斥锁
OS_MutexGrpRemove(OSTCBCurPtr, p_mutex);
// 获取等待互斥锁的任务列表
p_pend_list = &p_mutex->PendList;
if (p_pend_list->HeadPtr == (OS_TCB *)0) { // 有任何任务在等待互斥锁吗?
p_mutex->OwnerTCBPtr = (OS_TCB *)0; // 没有
p_mutex->OwnerNestingCtr = 0u;
CPU_CRITICAL_EXIT();
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE);
*p_err = OS_ERR_NONE;
return;
}
// 确定所有者是否继承了优先级
if (OSTCBCurPtr->Prio != OSTCBCurPtr->BasePrio) { // 所有者是否继承了优先级?
prio_new = OS_MutexGrpPrioFindHighest(OSTCBCurPtr); // 是,找到最高优先级的等待任务
prio_new = (prio_new > OSTCBCurPtr->BasePrio) ? OSTCBCurPtr->BasePrio : prio_new;
if (prio_new > OSTCBCurPtr->Prio) {
OS_RdyListRemove(OSTCBCurPtr);
OSTCBCurPtr->Prio = prio_new; // 降低所有者的优先级回到其原始优先级
OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(OSTCBCurPtr, prio_new);
OS_PrioInsert(prio_new);
OS_RdyListInsertTail(OSTCBCurPtr); // 在新的优先级下插入所有者到就绪列表
OSPrioCur = prio_new;
}
}
// 从等待列表头部获取 TCB
p_tcb = p_pend_list->HeadPtr;
p_mutex->OwnerTCBPtr = p_tcb; // 将互斥锁交给新所有者
p_mutex->OwnerNestingCtr = 1u;
OS_MutexGrpAdd(p_tcb, p_mutex);
// 信号互斥锁
OS_Post((OS_PEND_OBJ *)((void *)p_mutex),
p_tcb,
(void *)0,
0u,
ts);
// 退出临界区
CPU_CRITICAL_EXIT();
// 调用调度器
if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
OSSched(); // 运行调度器
}
// 追踪信号互斥锁退出
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE);
*p_err = OS_ERR_NONE;
}
/*
************************************************************************************************************************
* 清除互斥锁的内容
*
* 描述: 此函数由 OSMutexDel() 调用,用于清除互斥锁的内容
*
* 参数:
* p_mutex - 指向要清除的互斥锁的指针
* -------
*
* 返回值:
* 无
*
* 注意:
* 此函数是 uC/OS-III 的内部函数,您的应用程序不应调用它。
************************************************************************************************************************
*/
void OS_MutexClr (OS_MUTEX *p_mutex)
{
#if (OS_OBJ_TYPE_REQ > 0u)
p_mutex->Type = OS_OBJ_TYPE_NONE; // 标记数据结构为 NONE
#endif
#if (OS_CFG_DBG_EN > 0u)
p_mutex->NamePtr = (CPU_CHAR *)((void *)"?MUTEX"); // 设置调试名称
#endif
p_mutex->MutexGrpNextPtr = (OS_MUTEX *)0; // 初始化互斥锁组链表指针
p_mutex->OwnerTCBPtr = (OS_TCB *)0; // 初始化所有者任务控制块指针
p_mutex->OwnerNestingCtr = 0u; // 初始化所有者嵌套计数
#if (OS_CFG_TS_EN > 0u)
p_mutex->TS = 0u; // 初始化时间戳
#endif
OS_PendListInit(&p_mutex->PendList); // 初始化等待列表
}
/*
************************************************************************************************************************
* 添加/移除互斥锁到/从调试列表
*
* 描述: 这些函数由 uC/OS-III 调用,用于将互斥锁添加到或从调试列表中移除。
*
* 参数:
* p_mutex - 指向要添加或移除的互斥锁的指针
*
* 返回值:
* 无
*
* 注意:
* 这些函数是 uC/OS-III 的内部函数,您的应用程序不应调用它们。
************************************************************************************************************************
*/
#if (OS_CFG_DBG_EN > 0u)
void OS_MutexDbgListAdd (OS_MUTEX *p_mutex)
{
p_mutex->DbgNamePtr = (CPU_CHAR *)((void *)" ");
p_mutex->DbgPrevPtr = (OS_MUTEX *)0;
if (OSMutexDbgListPtr == (OS_MUTEX *)0) {
p_mutex->DbgNextPtr = (OS_MUTEX *)0;
} else {
p_mutex->DbgNextPtr = OSMutexDbgListPtr;
OSMutexDbgListPtr->DbgPrevPtr = p_mutex;
}
OSMutexDbgListPtr = p_mutex;
}
void OS_MutexDbgListRemove (OS_MUTEX *p_mutex)
{
OS_MUTEX *p_mutex_next;
OS_MUTEX *p_mutex_prev;
p_mutex_prev = p_mutex->DbgPrevPtr;
p_mutex_next = p_mutex->DbgNextPtr;
if (p_mutex_prev == (OS_MUTEX *)0) {
OSMutexDbgListPtr = p_mutex_next;
if (p_mutex_next != (OS_MUTEX *)0) {
p_mutex_next->DbgPrevPtr = (OS_MUTEX *)0;
}
p_mutex->DbgNextPtr = (OS_MUTEX *)0;
} else if (p_mutex_next == (OS_MUTEX *)0) {
p_mutex_prev->DbgNextPtr = (OS_MUTEX *)0;
p_mutex->DbgPrevPtr = (OS_MUTEX *)0;
} else {
p_mutex_prev->DbgNextPtr = p_mutex_next;
p_mutex_next->DbgPrevPtr = p_mutex_prev;
p_mutex->DbgNextPtr = (OS_MUTEX *)0;
p_mutex->DbgPrevPtr = (OS_MUTEX *)0;
}
}
#endif
/*
************************************************************************************************************************
* 互斥锁组添加
*
* 描述: 此函数由内核调用,用于将互斥锁添加到任务的互斥锁组中。
*
* 参数:
* p_tcb - 指向要赋予互斥锁的任务的 TCB(任务控制块)的指针。
* p_mutex - 指向要添加到组中的互斥锁的指针。
*
* 返回值:
* 无
*
* 注意:
* 1) 此函数是 uC/OS-III 的内部函数,您的应用程序不得调用它。
************************************************************************************************************************
*/
void OS_MutexGrpAdd (OS_TCB *p_tcb, OS_MUTEX *p_mutex)
{
p_mutex->MutexGrpNextPtr = p_tcb->MutexGrpHeadPtr; /* The mutex grp is not sorted add to head of list. */
p_tcb->MutexGrpHeadPtr = p_mutex;
}
/*
************************************************************************************************************************
* 互斥锁组移除
*
* 描述: 此函数由内核调用,用于从任务的互斥锁组中移除互斥锁。
*
* 参数:
* p_tcb - 指向要从中移除互斥锁的任务的 TCB(任务控制块)的指针。
* p_mutex - 指向要从组中移除的互斥锁的指针。
*
* 返回值:
* 无
*
* 注意:
* 1) 此函数是 uC/OS-III 的内部函数,您的应用程序不得调用它。
************************************************************************************************************************
*/
void OS_MutexGrpRemove (OS_TCB *p_tcb, OS_MUTEX *p_mutex)
{
// 定义一个指向互斥量指针的指针,用于遍历互斥量列表
OS_MUTEX **pp_mutex;
// 初始化遍历指针,使其指向TCB中互斥量组的头部指针
pp_mutex = &p_tcb->MutexGrpHeadPtr;
// 遍历互斥量列表,直到找到与p_mutex匹配的互斥量
while(*pp_mutex != p_mutex) {
// 移动遍历指针到下一个互斥量
pp_mutex = &(*pp_mutex)->MutexGrpNextPtr;
}
// 从列表中移除找到的互斥量,通过更新前一个互斥量的指针来跳过当前互斥量
*pp_mutex = (*pp_mutex)->MutexGrpNextPtr;
}
/*
************************************************************************************************************************
* 查找最高优先级等待的互斥量
*
* 描述: 此函数由内核调用,用于从一组互斥量中查找最高优先级的等待任务。
*
* 参数: p_tcb 是指向要处理的任务的TCB的指针。
*
* 返回值: 最高优先级的等待任务,如果没有找到则返回 OS_CFG_PRIO_MAX - 1u。
*
* 注意: 1) 此函数是 uC/OS-III 的内部函数,您的应用程序必须不得调用它。
************************************************************************************************************************
*/
OS_PRIO OS_MutexGrpPrioFindHighest (OS_TCB *p_tcb)
{
// 用于遍历互斥组的指针
OS_MUTEX **pp_mutex;
// 初始化最高优先级为次高优先级
OS_PRIO highest_prio;
// 临时存储当前遍历到的优先级
OS_PRIO prio;
// 指向互斥组挂起列表的头指针
OS_TCB *p_head;
// 初始化最高优先级为系统允许的最高优先级减一
highest_prio = (OS_PRIO)(OS_CFG_PRIO_MAX - 1u);
// 从任务控制块的互斥组头指针开始遍历
pp_mutex = &p_tcb->MutexGrpHeadPtr;
// 遍历互斥组链表,直到找到优先级最高的互斥组
while(*pp_mutex != (OS_MUTEX *)0) {
// 获取当前互斥组挂起列表的头指针
p_head = (*pp_mutex)->PendList.HeadPtr;
// 如果挂起列表不为空,则进一步检查优先级
if (p_head != (OS_TCB *)0) {
// 获取挂起列表头任务的优先级
prio = p_head->Prio;
// 如果当前优先级低于已知的最高优先级,则更新最高优先级
if(prio < highest_prio) {
highest_prio = prio;
}
}
// 移动到下一个互斥组指针
pp_mutex = &(*pp_mutex)->MutexGrpNextPtr;
}
// 返回找到的最高优先级
return (highest_prio);
}
/*
************************************************************************************************************************
* 互斥组全部释放
*
* 描述: 该函数由内核调用,用于释放(解除锁定)一个组中的所有互斥量。通常在删除任务时使用。
*
* 参数: p_tcb 是指向要处理的任务的TCB的指针。
*
* 返回: 无。
*
* 注意: 1) 该函数是uC/OS-III的内部函数,您的应用程序不得调用它。
************************************************************************************************************************
*/
void OS_MutexGrpPostAll(OS_TCB *p_tcb)
{
OS_MUTEX *p_mutex;
OS_MUTEX *p_mutex_next;
CPU_TS ts;
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb_new;
// 获取任务的互斥量组头指针
p_mutex = p_tcb->MutexGrpHeadPtr;
// 遍历互斥量组中的所有互斥量
while (p_mutex != (OS_MUTEX *)0) {
// 跟踪互斥量的释放操作
OS_TRACE_MUTEX_POST(p_mutex);
// 获取下一个互斥量
p_mutex_next = p_mutex->MutexGrpNextPtr;
#if (OS_CFG_TS_EN > 0u)
// 获取当前时间戳
ts = OS_TS_GET();
p_mutex->TS = ts;
#else
ts = 0u;
#endif
// 从所有者组中移除互斥量
OS_MutexGrpRemove(p_tcb, p_mutex);
// 获取等待队列
p_pend_list = &p_mutex->PendList;
// 检查是否有任务在等待该互斥量
if (p_pend_list->HeadPtr == (OS_TCB *)0) {
// 没有任务等待,重置互斥量的所有者信息
p_mutex->OwnerNestingCtr = 0u;
p_mutex->OwnerTCBPtr = (OS_TCB *)0;
} else {
// 获取等待队列头部的任务
p_tcb_new = p_pend_list->HeadPtr;
// 将互斥量分配给新的所有者
p_mutex->OwnerTCBPtr = p_tcb_new;
p_mutex->OwnerNestingCtr = 1u;
// 将互斥量添加到新所有者的互斥量组中
OS_MutexGrpAdd(p_tcb_new, p_mutex);
// 释放互斥量
OS_Post((OS_PEND_OBJ *)((void *)p_mutex),
p_tcb_new,
(void *)0,
0u,
ts);
}
// 继续处理下一个互斥量
p_mutex = p_mutex_next;
}
}
#endif /* OS_CFG_MUTEX_EN */
标签:ERR,UcOs,0u,III,互斥,源码,mutex,MUTEX,OS
From: https://www.cnblogs.com/lanlincmos/p/18518322