等待一个邮箱中的消息,OSMboxPend()

程序清单 L6.15是OSMboxPend()函数的源代码。同样,它和OSSemPend()也很相似,因此,在这里只讲述其中的不同之处。OSMboxPend()首先检查该事件控制块是由OSMboxCreate()函数建立的[L6.15(1)]。当.OSEventPtr域是一个非NULL的指针时,说明该邮箱中有可用的消息[L6.15(2)]。这种情况下,OSMboxPend()函数将该域的值复制到局部变量msg中,然后将.OSEventPtr置为NULL[L6.15(3)]。这正是我们所期望的,也是执行OSMboxPend()函数最快的路径。
如果此时邮箱中没有消息是可用的(.OSEventPtr域是NULL指针),OSMboxPend()函数检查它的调用者是否是中断服务子程序[L6.15(4)]。象OSSemPend()函数一样,不能在中断服务子程序中调用OSMboxPend(),因为中断服务子程序是不能等待的。这里的代码同样是为了以防万一。但是,如果邮箱中有可用的消息,即使从中断服务子程序中调用OSMboxPend()函数,也一样是成功的。
如果邮箱中没有可用的消息,OSMboxPend()的调用任务就被挂起,直到邮箱中有了消息或者等待超时[L6.15(5)]。当有其它的任务向该邮箱发送了消息后(或者等待时间超时),这时,该任务再一次成为最高优先级任务,OSSched()返回。这时,OSMboxPend()函数要检查是否有消息被放到该任务的任务控制块中[L6.15(6)]。如果有,那么该次函数调用成功,对应的消息被返回到调用函数。程序清单 L6.15 等待一个邮箱中的消息
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
    void  *msg;

    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {	              (1)
        OS_EXIT_CRITICAL();
        *err = OS_ERR_EVENT_TYPE;
        return ((void *)0);
    }
    msg = pevent->OSEventPtr;
    if (msg != (void *)0) {	                                       (2)
        pevent->OSEventPtr = (void *)0;	                           (3)
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
    } else if (OSIntNesting > 0) {	                                (4)
        OS_EXIT_CRITICAL();
        *err = OS_ERR_PEND_ISR;
    } else {
        OSTCBCur->OSTCBStat |= OS_STAT_MBOX;	                      (5)
        OSTCBCur->OSTCBDly   = timeout;
        OSEventTaskWait(pevent);
        OS_EXIT_CRITICAL();
        OSSched();
        OS_ENTER_CRITICAL();
        if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) {	            (6)
            OSTCBCur->OSTCBMsg      = (void *)0;
            OSTCBCur->OSTCBStat     = OS_STAT_RDY;
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
            OS_EXIT_CRITICAL();
            *err                    = OS_NO_ERR;
        } else if (OSTCBCur->OSTCBStat & OS_STAT_MBOX) {	          (7)
            OSEventTO(pevent);	                                    (8)
            OS_EXIT_CRITICAL();
            msg                     = (void *)0;	                  (9)
            *err                    = OS_TIMEOUT;
        } else {            msg                     = pevent->OSEventPtr;	        (10)
            pevent->OSEventPtr      = (void *)0;                            (11)
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;	             (12)
            OS_EXIT_CRITICAL();
            *err                    = OS_NO_ERR;
        }
    }
    return (msg);
}

在OSMboxPend()函数中,通过检查任务控制块中的.OSTCBStat域中的OS_STAT_MBOX位,可以知道是否等待超时。如果该域被置1,说明任务等待已经超时[L6.15(7)]。这时,通过调用函数OSEventTo()可以将任务从邮箱的等待列表中删除[L6.15(8)]。因为此时邮箱中没有消息,所以返回的指针是NULL[L6.15(9)]。如果OS_STAT_MBOX位没有被置1,说明所等待的消息已经被发出。OSMboxPend()的调用函数得到指向消息的指针[L6.15(10)]。此后,OSMboxPend()函数通过将邮箱事件控制块的.OSEventPtr域置为NULL清空该邮箱,并且要将任务任务控制块中指向邮箱事件控制块的指针删除[L6.15(12)]。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值