ucosii---------信号量&邮箱

typedef struct os_event {
    INT8U    OSEventType;                    /* Type of event control block (see OS_EVENT_TYPE_xxxx)    */
    void    *OSEventPtr;                     /* Pointer to message or queue structure                   */
    INT16U   OSEventCnt;                     /* Semaphore Count (not used if other EVENT type)          */
#if OS_LOWEST_PRIO <= 63
    INT8U    OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur */
    INT8U    OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                */
    INT8U    OSEventName[OS_EVENT_NAME_SIZE];
} OS_EVENT;

信号量和邮箱都是使用OS_EVENT这个结构体。在OSInit()初始化函数里面会创建OS_EVENT结构体的链表。
` OSInitHookBegin(); /* Call port specific initialization code */

OS_InitMisc();                                               /* Initialize miscellaneous variables       */

OS_InitRdyList();                                            /* Initialize the Ready List                */

OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */

OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */`

最后一行OS_InitEventList();就是建立OS_EXENT链表的。
感觉很像任务。任务有OS_TCB,事件有OS_EVENT;任务有OS_TCBInit(通常被OSTaskCreate调用)函数从OSTCBFreeList为首的链表里面提取空闲OS_TCB,事件有OSSemCreate或OSMboxCreate(OS_EVNET相比之下并没有类似于OS_TCBInit的函数)。
OS_EVENT的类别由由选用的函数决定,选OSSemCreate,创建出来的就是Sem类型,反之是mbox类型。

    pevent = OSEventFreeList;                    /* Get next free event control block                  */
    if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }

取用OS_EVENT。就跟OSTaskCreate中的OS_TCBInit一样。

    if (pevent != (OS_EVENT *)0) {
        pevent->OSEventType    = OS_EVENT_TYPE_MBOX;
        pevent->OSEventCnt     = 0;
        pevent->OSEventPtr     = pmsg;           /* Deposit message in event control block             */
#if OS_EVENT_NAME_SIZE > 1
        pevent->OSEventName[0] = '?';
        pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
        OS_EventWaitListInit(pevent);
    }

如果取用成功(指针变量不为空),进行初始化。其中OS_EventWaitListInit函数将每一个OS_EVENT具有的OSEventGrp和OSEventTbl清零(这两个很像OSRdyGrp和OSRdyTbl,就绪表),事件可以通过查找他们各自的OSEventGrp和OSEventTbl来确定应该出发哪一个事件(OSEventTbl表中所记录的优先级最高的任务)。由OS_EVENT自己查找的方法通常在OSSemPend和OSMboxPend中体现。
邮箱:

    pmsg = pevent->OSEventPtr;
    if (pmsg != (void *)0) {                          /* See if there is already a message             */
        pevent->OSEventPtr = (void *)0;               /* Clear the mailbox                             */
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return (pmsg);                                /* Return the message received (or NULL)         */
    }

由于定义方式不同,返回变量也不同。
我写的程序里面邮箱的初始化OSMboxCreate((void*)0);这样的话,第一遍经过OSMboxPend时就进入到上述判断语句。
而进入接下来的代码。

    OSTCBCur->OSTCBStat     |= OS_STAT_MBOX;          /* Message not available, task will pend         */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;               /* Load timeout in TCB                           */
    OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
    OS_EXIT_CRITICAL();
    OS_Sched();                                       /* Find next highest priority task ready to run  */
    OS_ENTER_CRITICAL();

先对当前的OS_TCB进行操作,然后调用OS_EventTaskWait把当前任务的优先级写入OSEventTbl,再从OSRdyTbl把此优先级从表中拿出。最后由OS_Sched切换成优先级最高的任务。

    switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
        case OS_STAT_PEND_OK:
             pmsg =  OSTCBCur->OSTCBMsg;
            *perr =  OS_ERR_NONE;
             break;

        case OS_STAT_PEND_ABORT:
             pmsg = (void *)0;
            *perr =  OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */
             break;

        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             pmsg = (void *)0;
            *perr =  OS_ERR_TIMEOUT;                  /* Indicate that we didn't get event within TO   */
             break;
    }

主要是这段代码

            pmsg =  OSTCBCur->OSTCBMsg;
            *perr =  OS_ERR_NONE;
             break;

它与结束时的

return (pmsg); 

相对应。这里就体现出OSMboxPend和OSSemPend的不同。

void  OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
void  *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)

OSSemPend函数压根就没想过返回任何东西,而要返回OSMboxPend所传送的邮件。

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 > 0)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OSTCBCur->OSTCBMsg           = (void      *)0;    /* Clear  received message                       */
    OS_EXIT_CRITICAL();
    return (pmsg); 

问题是结尾为什么把当前的OS_TCB又设置一遍?
下面再谈谈OSMboxPost函数。

if (pevent->OSEventGrp != 0) {                    /* See if any task pending on mailbox            */
                                                      /* Ready HPT waiting on event                    */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
        return (OS_ERR_NONE);
    }

通常会经由这段代码返回。代码先检查事件中的OSEventTbl有没有等待任务。应该是有的。然后就是调用OS_EventTaskRdy这个函数了。

    y    = OSUnMapTbl[pevent->OSEventGrp];              /* Find HPT waiting for message                */
    x    = OSUnMapTbl[pevent->OSEventTbl[y]];
    prio = (INT8U)((y << 3) + x);                       /* Find priority of task getting the msg       */

OS_EventTaskRdy函数根据OS_EVENT提供的信息,找出OSEventTbl中优先级最高的优先级。

ptcb                  =  OSTCBPrioTbl[prio];        /* Point to this task's OS_TCB                 */
    ptcb->OSTCBDly        =  0;

再OSTCBPrioTbl中找到相应的OS_TCB,进行一系列操作。

    if ((ptcb->OSTCBStat &   OS_STAT_SUSPEND) == OS_STAT_RDY) {
        OSRdyGrp         |=  ptcb->OSTCBBitY;           /* Put task in the ready to run list           */
        OSRdyTbl[y]      |=  ptcb->OSTCBBitX;
    }
    OS_EventTaskRemove(ptcb, pevent);                   /* Remove this task from event   wait list     */

把任务写入OSRdyTbl中。再用EventTaskRemove将对应优先级从OSEventTbl移除(此OS_EVENT专用的)。

#if (OS_EVENT_MULTI_EN > 0)
    if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {   /* Remove this task from events' wait lists    */
        OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
        ptcb->OSTCBEventPtr       = (OS_EVENT  *)pevent;/* Return event as first multi-pend event ready*/
    }
#endif

这段代码应该是关于互斥量。
至此,三个比较重要的函数(OSMboxCreate,OSMboxPend,OSMboxPost)介绍完了。信号量跟邮箱差不多。参考一下就应该差不多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值