OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4897|回复: 1

有点难!高手赐教!对OSMutexPend函数的理解有障碍,被两个问题困扰了两天。

[复制链接]

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
101
金钱
101
注册时间
2018-5-19
在线时间
10 小时
发表于 2018-9-7 20:11:35 | 显示全部楼层 |阅读模式
1金钱
看过这个函数之后,被两个问题困扰了两天:
1. “ pevent2 = ptcb->OSTCBEventPtr ”,互斥信号量所有者在获得信号量之后,并未将事件控制块的地址保存到其任务控制块的OSTCBEventPtr项中(至少查看相关代码没发现),那么事后 ptcb->OSTCBEventPtr的内容从何而来?
2. 代码中,为什么要判断互斥信号量占有者是否就绪?是因为它在获得互斥信号量之后、归还信号量之前(占据着信号量),它有可能被阻塞或挂起?还有一种被阻塞的可能,在该任务获得互斥信号量之后,如果马上再请求一次互斥信号量,据自己对代码的分析,会导致此任务被阻塞掉,不知道我这个分析是否正确?

以下是OSMutexPend函数的原码,及自己的部分注释:
//请求互斥信号量
void  OSMutexPend (OS_EVENT  *pevent,
                   INT32U     timeout,
                   INT8U     *perr)
{
    INT8U      pcp;                                        /* Priority Ceiling Priority (PCP)          */
    INT8U      mprio;                                      /* Mutex owner priority                     */
    BOOLEAN    rdy;                                        /* Flag indicating task was ready           */
    OS_TCB    *ptcb;
    OS_EVENT  *pevent2;
    INT8U      y;
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    if (OSIntNesting > 0u) {                               /* See if called from ISR ...               */
        *perr = OS_ERR_PEND_ISR;                           /* ... can't PEND from an ISR               */
        return;
    }
    if (OSLockNesting > 0u) {                              /* See if called with scheduler locked ...  */
        *perr = OS_ERR_PEND_LOCKED;                        /* ... can't PEND when locked               */
        return;
    }
/*$PAGE*/
    OS_ENTER_CRITICAL();
    pcp = (INT8U)(pevent->OSEventCnt >> 8u);               /* Get PCP from mutex                       */
                                                           /* Is Mutex available?                      */
    if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {  /*   如果互斥信号量可用    */
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;       /* Yes, Acquire the resource                */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;         /*      Save priority of owning task        */
        pevent->OSEventPtr  = (void *)OSTCBCur;            /*      Point to owning task's OS_TCB       */
        if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
            (OSTCBCur->OSTCBPrio <= pcp)) {                /*      PCP 'must' have a SMALLER prio ...  */
             OS_EXIT_CRITICAL();                           /*      ... than current task!              */
            *perr = OS_ERR_PCP_LOWER;
        } else {
             OS_EXIT_CRITICAL();
            *perr = OS_ERR_NONE;
        }
        return;//得到互斥信号量,返回。
    }
       
        //当前任务发现无互斥信号量可用,执行以下代码:
    if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
        mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /*  获得互斥信号量占有者的任务优先级mprio   */
        ptcb  = (OS_TCB *)(pevent->OSEventPtr);  /*   获得互斥信号量占有者的任务控制块的指针   */
        if (ptcb->OSTCBPrio > pcp) {             /*   如果互斥信号量占有者的任务优先级比继承优先级pcp(需临时抬升互斥信号量占有者的优先级为pcp)低*/
            if (mprio > OSTCBCur->OSTCBPrio) {   /*   如果互斥信号量占有者的优先级比当前请求互斥信号量的任务的优先级低,就需要继承优先级 */
                y = ptcb->OSTCBY;
                if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) {      /* 如果互斥信号量占有者已就绪,那就清空此任务的就绪表?????????????????? */
                    OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;     
                    if (OSRdyTbl[y] == 0u) {                     
                        OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
                    }
                    rdy = OS_TRUE;
                } else {                /*  如果互斥信号量占有者未就绪,那就清空此任务对互斥信号量的等待表??????????????????????  */
                    pevent2 = ptcb->OSTCBEventPtr; /*   互斥信号量的占有者,什么时候保存了事件控制块的指针至其任务控制块的OSTCBEventPtr项??????????  */
                    if (pevent2 != (OS_EVENT *)0) {               /* Remove from event wait list       */
                        y = ptcb->OSTCBY;
                        pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
                        if (pevent2->OSEventTbl[y] == 0u) {
                            pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
                        }
                    }
                    rdy = OS_FALSE;                        /* No                                       */
                }
                ptcb->OSTCBPrio = pcp;                     /*  抬升互斥信号量占有者的任务优先级至PCP  */
#if OS_LOWEST_PRIO <= 63u
                ptcb->OSTCBY    = (INT8U)( ptcb->OSTCBPrio >> 3u);
                ptcb->OSTCBX    = (INT8U)( ptcb->OSTCBPrio & 0x07u);
#else
                ptcb->OSTCBY    = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);
                ptcb->OSTCBX    = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);
#endif
                ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
                ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);

                if (rdy == OS_TRUE) {                      /*  如果互斥信号量占有者已就绪,就按新的优先级pcp来设置该任务的就绪表   */
                    OSRdyGrp               |= ptcb->OSTCBBitY; /* ... make it ready at new priority.   */
                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                } else {                                  /*  如果互斥信号量占有者未就绪,就按抬升后的优先级pcp来设置该任务对互斥信号量的等待表*/
                    pevent2 = ptcb->OSTCBEventPtr;
                    if (pevent2 != (OS_EVENT *)0) {        /* Add to event wait list                   */
                        pevent2->OSEventGrp               |= ptcb->OSTCBBitY;
                        pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
                OSTCBPrioTbl[pcp] = ptcb;    /*  按抬升后的优先级pcp来设置任务优先级指针表   */
            }
        }
    }
    OSTCBCur->OSTCBStat     |= OS_STAT_MUTEX;         /* Mutex not available, pend current task        */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;               /*   设置等待互斥信号量的时限    */
    OS_EventTaskWait(pevent);                         /*   先记录此任务对互斥信号量的等待,然后阻塞自己    */
    OS_EXIT_CRITICAL();
    OS_Sched();                                       /* Find next highest priority task ready    重新调度任务     */
       
        //重新获得CPU使用权
    OS_ENTER_CRITICAL();
    switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
        case OS_STAT_PEND_OK:
             *perr = OS_ERR_NONE;
             break;

        case OS_STAT_PEND_ABORT:
             *perr = OS_ERR_PEND_ABORT;               /* Indicate that we aborted getting mutex        */
             break;

        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             *perr = OS_ERR_TIMEOUT;                  /* Indicate that we didn't get mutex within TO   */
             break;
    }
    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */
    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */
    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */
#if (OS_EVENT_MULTI_EN > 0u)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OS_EXIT_CRITICAL();
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2018-9-8 01:34:33 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 04:26

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表