首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

uC/OSIII的消息队列处理机制(5)

uC/OSIII的消息队列处理机制(5)

OSQPend()函数的处理过程就是这样的,具体函数内容如下:
void *OSQPend (OS_Q *p_q,
                OS_TICK timeout,
                OS_OPT opt,
                OS_MSG_SIZE *p_msg_size,
                CPU_TS *p_ts,
                OS_ERR *p_err)
{
    OS_PEND_DATA pend_data;
    void *p_void;
    CPU_SR_ALLOC();
    /*参数检查代码略*/
CPU_CRITICAL_ENTER();
    p_void = OS_MsgQGet(&p_q->MsgQ,      /* 判断队列里是否有已经被推送过的消息*/
p_msg_size,
                        p_ts,
                        p_err);
    if (*p_err == OS_ERR_NONE) {
        CPU_CRITICAL_EXIT();
        return (p_void); /* 如果队列里有消息存在,直接返回,不pend */
    }
      if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
             /*如果是在中断中,不能pend,必须立即返回*/
CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_SCHED_LOCKED;
            return ((void *)0);
        }

    OS_CRITICAL_ENTER_CPU_EXIT();
  /*锁定调度器*/
OS_Pend(&pend_data,    /* 准备进入阻塞等待状态,将挂起表等数据结构都准备好*/
            (OS_PEND_OBJ *)((void *)p_q),
            OS_TASK_PEND_ON_Q,
            timeout);
    OS_CRITICAL_EXIT_NO_SCHED();
  /*退出调度锁定,并且不调度*/
OSSched(); /*进入调度点,切换到其他任务,到此,本任务处于暂停状态,在等待到消息
                          到达之前,不会再执行以下代码  */

/* 以下为从别的任务切换回来继续执行的代码,可能为pend获得,也可能为超时、删除了,
pend获得的内容是被保留在本任务TCB的MsgPtr和MsgSize中 */
CPU_CRITICAL_ENTER();
    switch (OSTCBCurPtr->PendStatus) {
        case OS_STATUS_PEND_OK: /* 是正常推送过来的消息 */
             /*从本任务的TCB中MsgPtr和MsgSize中取出消息*/
p_void = OSTCBCurPtr->MsgPtr;

            *p_msg_size = OSTCBCurPtr->MsgSize;
             if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
             }
            *p_err = OS_ERR_NONE;
             break;
        case OS_STATUS_PEND_ABORT: /* 如果是消息队列被abort的,返回空  */
p_void = (void *)0;
            *p_msg_size = (OS_MSG_SIZE)0;
             if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
             }
            *p_err = OS_ERR_PEND_ABORT;
    /* 报错为OS_ERR_PEND_ABORT  */
             break;
        case OS_STATUS_PEND_TIMEOUT: /* 如果是等待超时,返回空*/
p_void = (void *)0;
            *p_msg_size = (OS_MSG_SIZE)0;
             if (p_ts != (CPU_TS *)0) {
                *p_ts = (CPU_TS )0;
             }
            *p_err = OS_ERR_TIMEOUT;   
/* 报错为OS_ERR_TIMEOUT */
             break;
        case OS_STATUS_PEND_DEL: /* 如果是消息队列被删除的,返回空  */
p_void = (void *)0;
            *p_msg_size = (OS_MSG_SIZE)0;
             if (p_ts != (CPU_TS *)0) {
                *p_ts = OSTCBCurPtr->TS;
             }
            *p_err = OS_ERR_OBJ_DEL;
  /* 报错为OS_ERR_OBJ_DEL */
             break;
        default:
             p_void = (void *)0;
            *p_msg_size = (OS_MSG_SIZE)0;
            *p_err = OS_ERR_STATUS_INVALID;
             break;
    }
    CPU_CRITICAL_EXIT();
    return (p_void);
}
至于任务消息队列等待函数void *OSTaskQPend()与此过程基本相同,也是分两部分,而且内部调用的函数也都一样,只是在传递参数的时候省去了将TCB写入对应OS_Q的任务挂起表中的过程,也不对OS_PEND_DATA中被等待的消息队列赋值,因为消息被推送后,会直接被推送到任务TCB自己的存储空间中,不需要这些数据结构做查找。对任务消息队列等待函数不再做过多介绍。
多对象等待函数OS_OBJ_QTY  OSMultiPend()中处理过程与此也是基本相同,而最大的区别是内部调用的函数不太一样,它在状态一阶段是用OS_MultiPendWait进行参数配置,然后进入OSSched()调度点,切换到其他任务;收到消息后,进行返回状态错误判断,就直接返回,并不提取消息内容,因为MultiPend里面等待的对象太多了,而且数目也不固定,它的消息内容提取工作交给应用程序员自己去完成。
继承事业,薪火相传
返回列表