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

来源:互联网 发布:复杂网络应用实例 编辑:程序博客网 时间:2024/06/04 19:21

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;}
原创粉丝点击