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里面等待的对象太多了,而且数目也不固定,它的消息内容提取工作交给应用程序员自己去完成。 |