uC/OS-III之资源管理--互斥型信号量

1.uC/OS-III支持一种特殊的二进制信号量–互斥型信号量。

2.互斥型信号量通过安全优先级继承机制(一旦一个具有高优先级的任务H想要访问共享资源,占有该资源的任务的优先级将被提升至与任务H一样),来避免无界优先级翻转的问题。

3.互斥型信号量是一种被定义为OS_MUTEX数据类型的内核对象,它的定义位于os.h中。
注:与信号量一样,只有任务才能使用互斥型信号量(中断服务程序不可以)。

typedef  struct  os_mutex            OS_MUTEX;              // 625行

struct  os_mutex {                                          // 817行 - 830行
    OS_OBJ_TYPE          Type;                              // 互斥信号量的类型,必须设置成OS_OBJ_TYPE_MUTEX
    CPU_CHAR            *NamePtr;                           // 互斥信号量的名称
    OS_PEND_LIST         PendList;                          // 任务挂起表
#if OS_CFG_DBG_EN > 0u                                      // 调试相关
    OS_MUTEX            *DbgPrevPtr;
    OS_MUTEX            *DbgNextPtr;
    CPU_CHAR            *DbgNamePtr;
#endif
    OS_TCB              *OwnerTCBPtr;                       // 指向占有该互斥信号量的任务的任务控制块OS_TCB
    OS_PRIO              OwnerOriginalPrio;                 // 记录任务占有互斥信号量之前的优先级
    OS_NESTING_CTR       OwnerNestingCtr;                   // 互斥信号量的嵌套深度
    CPU_TS               TS;                                // 记录上一次被释放的时间
};

4.互斥型信号量通过OSMutexCreate()创建,它的定义位于os_mutex.c中。

void  OSMutexCreate (OS_MUTEX    *p_mutex,
                     CPU_CHAR    *p_name,
                     OS_ERR      *p_err)                    // 66行 - 118行
{
    CPU_SR_ALLOC();                                         // 声明变量cpu_sr,用来临时存储CPU的状态寄存器

#ifdef OS_SAFETY_CRITICAL                                   // 系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508                          // 系统安全性检查(IEC61508)
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
       *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用
        *p_err = OS_ERR_CREATE_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();                                   // 进入临界区
    p_mutex->Type              =  OS_OBJ_TYPE_MUTEX;        // 标记结构体为互斥型信号量
    p_mutex->NamePtr           =  p_name;
    p_mutex->OwnerTCBPtr       = (OS_TCB       *)0;
    p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)0;         // 当OwnerNestingCtr为0时,互斥信号量可用
    p_mutex->TS                = (CPU_TS        )0;
    p_mutex->OwnerOriginalPrio =  OS_CFG_PRIO_MAX;
    OS_PendListInit(&p_mutex->PendList);                    // 初始化挂起表

#if OS_CFG_DBG_EN > 0u
    OS_MutexDbgListAdd(p_mutex);
#endif
    OSMutexQty++;                                           // 系统互斥信号量数目加1

    CPU_CRITICAL_EXIT();                                    // 退出临界区
    *p_err = OS_ERR_NONE;
}

5.等待互斥信号量使用OSMutexPend(),它的定义位于os_mutex.c中。

void  OSMutexPend (OS_MUTEX   *p_mutex,
                   OS_TICK     timeout,
                   OS_OPT      opt,
                   CPU_TS     *p_ts,
                   OS_ERR     *p_err)                         // 329行 - 493行
{
    OS_PEND_DATA  pend_data;
    OS_TCB       *p_tcb;
    CPU_SR_ALLOC();                                           // 声明变量cpu_sr,用来临时存储CPU的状态寄存器

#ifdef OS_SAFETY_CRITICAL                                   // 系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用该函数
       *p_err = OS_ERR_PEND_ISR;
        return;
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u                                  // 允许进行参数检查
    if (p_mutex == (OS_MUTEX *)0) {                         // 无效的参数
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
    switch (opt) {
        case OS_OPT_PEND_BLOCKING:
        case OS_OPT_PEND_NON_BLOCKING:
             break;
        default:                                            // 无效的选项
             *p_err = OS_ERR_OPT_INVALID;
             return;
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u                             // 允许进行类型检查
    if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {               // 确保互斥型已被创建
        *p_err = OS_ERR_OBJ_TYPE;
        return;
    }
#endif

    if (p_ts != (CPU_TS *)0) {
       *p_ts  = (CPU_TS  )0;                                // 初始化返回的时间戳参数
    }

    CPU_CRITICAL_ENTER();                                   // 进入临界区
    if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)0) {    // 嵌套层数OwnerNestingCtr为0时,表示互斥信号量可用
        p_mutex->OwnerTCBPtr       =  OSTCBCurPtr;
        p_mutex->OwnerOriginalPrio =  OSTCBCurPtr->Prio;
        p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;
        if (p_ts != (CPU_TS *)0) {
           *p_ts                   = p_mutex->TS;           // 返回上次释放互斥信号量的时间
        }
        CPU_CRITICAL_EXIT();                                // 退出临界区
        *p_err                     =  OS_ERR_NONE;
        return;
    }
                                                            // 互斥信号量不可用
    if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) {              // 当前任务正在使用互斥信号量
        p_mutex->OwnerNestingCtr++;                         // 嵌套层数加1
        if (p_ts != (CPU_TS *)0) {
           *p_ts  = p_mutex->TS;
        }
        CPU_CRITICAL_EXIT();                                // 退出临界区
        *p_err = OS_ERR_MUTEX_OWNER;                        // 说明一下当前任务已拥有该互斥信号量
        return;
    }

    if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    // 非阻塞型
        CPU_CRITICAL_EXIT();                                // 退出临界区
        *p_err = OS_ERR_PEND_WOULD_BLOCK;
        return;
    } else {                                                // 阻塞型
        if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {    // 调度器是锁定
            CPU_CRITICAL_EXIT();                            // 退出临界区
            *p_err = OS_ERR_SCHED_LOCKED;
            return;
        }
    }
                                                            // 阻塞型
    OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  // 进入临界区,使能中断
    p_tcb = p_mutex->OwnerTCBPtr;                           // 执行占有该互斥信号量的任务的任务控制块OS_TCB
    if (p_tcb->Prio > OSTCBCurPtr->Prio) {                  // 拥有互斥信号量的任务的优先级低于当前任务的优先级
        switch (p_tcb->TaskState) {
            case OS_TASK_STATE_RDY:
                 OS_RdyListRemove(p_tcb);                   // 把当前任务从就绪表中删除
                 p_tcb->Prio = OSTCBCurPtr->Prio;           // 提升拥有互斥信号量的任务的优先级
                 OS_PrioInsert(p_tcb->Prio);                // 更新优先级位映射表
                 OS_RdyListInsertHead(p_tcb);               // 插入到任务就绪表中
                 break;
            case OS_TASK_STATE_DLY:
            case OS_TASK_STATE_DLY_SUSPENDED:
            case OS_TASK_STATE_SUSPENDED:
                 p_tcb->Prio = OSTCBCurPtr->Prio;           // 仅仅提高拥有互斥信号量的任务的优先级
                 break;
            case OS_TASK_STATE_PEND:                        // 改变在挂起表中的位置
            case OS_TASK_STATE_PEND_TIMEOUT:
            case OS_TASK_STATE_PEND_SUSPENDED:
            case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                 OS_PendListChangePrio(p_tcb,
                                       OSTCBCurPtr->Prio);  // 改变挂起表中的优先级
                 break;

            default:
                 OS_CRITICAL_EXIT();                        // 退出临界区
                 *p_err = OS_ERR_STATE_INVALID;
                 return;
        }
    }

    OS_Pend(&pend_data,                                     // ???
             (OS_PEND_OBJ *)((void *)p_mutex),
             OS_TASK_PEND_ON_MUTEX,
             timeout);

    OS_CRITICAL_EXIT_NO_SCHED();                            // 退出临界区,不调度
    OSSched();                                              // 执行调度程序

    CPU_CRITICAL_ENTER();                                   // 进入临界区
    switch (OSTCBCurPtr->PendStatus) {
        case OS_STATUS_PEND_OK:                             // 得到互斥信号量
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             *p_err = OS_ERR_NONE;
             break;
        case OS_STATUS_PEND_ABORT:                          // 等待被禁止
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             *p_err = OS_ERR_PEND_ABORT;
             break;
        case OS_STATUS_PEND_TIMEOUT:                        // 等待超时
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = (CPU_TS  )0;
             }
             *p_err = OS_ERR_TIMEOUT;
             break;
        case OS_STATUS_PEND_DEL:                            // 互斥信号量被删除
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             *p_err = OS_ERR_OBJ_DEL;
             break;
        default:
             *p_err = OS_ERR_STATUS_INVALID;
             break;
    }
    CPU_CRITICAL_EXIT();                                    // 退出临界区
}

6.任务释放互斥型信号量使用OSMutexPost(),它的定义位于os_mutex.c中。

void  OSMutexPost (OS_MUTEX  *p_mutex,
                   OS_OPT     opt,
                   OS_ERR    *p_err)                           // 636行 - 727行
{
    OS_PEND_LIST  *p_pend_list;
    OS_TCB        *p_tcb;
    CPU_TS         ts;
    CPU_SR_ALLOC();                                         // 声明变量cpu_sr,用来临时保存CPU的状态寄存器

#ifdef OS_SAFETY_CRITICAL                                   // 允许进行系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用该函数
       *p_err = OS_ERR_POST_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

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u                             // 允许进行目标类型检查
    if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {               // 该对象不是互斥型信号量
        *p_err = OS_ERR_OBJ_TYPE;
        return;
    }
#endif

    CPU_CRITICAL_ENTER();                                   // 进入临界区
    if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) {              // 当前任务不是拥有该互斥型信号量的任务
        CPU_CRITICAL_EXIT();                                // 退出临界区
        *p_err = OS_ERR_MUTEX_NOT_OWNER;
        return;
    }

    OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  // 进入临界区,使能中断
    ts          = OS_TS_GET();                              // 获取时间戳
    p_mutex->TS = ts;
    p_mutex->OwnerNestingCtr--;                             // 减少互斥信号量的嵌套层数
    if (p_mutex->OwnerNestingCtr > (OS_NESTING_CTR)0) {     // 嵌套层数不为0,表示操作未完成
        OS_CRITICAL_EXIT();                                 // 退出临界区
        *p_err = OS_ERR_MUTEX_NESTING;
        return;
    }

    p_pend_list = &p_mutex->PendList;                       // 获取挂起表
    if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) {         // 挂起表为空(没有任务等待该互斥信号量)
        p_mutex->OwnerTCBPtr     = (OS_TCB       *)0;
        p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0;
        OS_CRITICAL_EXIT();                                 // 退出临界区
        *p_err = OS_ERR_NONE;
        return;
    }
                                                            // 挂起表不为空
    if (OSTCBCurPtr->Prio != p_mutex->OwnerOriginalPrio) {  // 任务的当前优先级与它之前的优先级不同
        OS_RdyListRemove(OSTCBCurPtr);                      // 把当前任务从就绪表中删除
        OSTCBCurPtr->Prio = p_mutex->OwnerOriginalPrio;     // 恢复其之前的优先级
        OS_PrioInsert(OSTCBCurPtr->Prio);                   // 更新优先级位映射表
        OS_RdyListInsertTail(OSTCBCurPtr);                  // 插入到就绪表中的尾部
        OSPrioCur         = OSTCBCurPtr->Prio;
    }
                                                            // 获取挂起表中的头部的OS_TCB
    p_tcb                      = p_pend_list->HeadPtr->TCBPtr;
    p_mutex->OwnerTCBPtr       = p_tcb;                     // 给互斥型信号量一个新的拥有者
    p_mutex->OwnerOriginalPrio = p_tcb->Prio;
    p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;

    OS_Post((OS_PEND_OBJ *)((void *)p_mutex),               // 发送互斥型信号量
            (OS_TCB      *)p_tcb,
            (void        *)0,
            (OS_MSG_SIZE  )0,
            (CPU_TS       )ts);

    OS_CRITICAL_EXIT_NO_SCHED();                            // 退出临界区,不调度

    if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
        OSSched();                                          // 执行调度程序
    }
    *p_err = OS_ERR_NONE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值