【Ucos-III源码分析】——等待多个内核对象
一、等待多个内核对象
这里ucos对于等待多个内核对象有一定的限制,而且这个函数也有一定的不好
1、等待多个内核对象只能是信号量或者消息队列,不能是别的内核对象,但是有多个。
2、等待多个内核对象会因为其中一个释放就解除等待,不会因为说需要等待到所有的内核对象都释放完成。
等待函数:OSPendMulti里面主要包含了这些内容
valid = OS_PendMultiValidate(p_pend_data_tbl, /* -------- Validate objects to be OS_SEM or OS_Q ------- */
tbl_size);
//------------------------------------------------------------------------------
CPU_BOOLEAN OS_PendMultiValidate (OS_PEND_DATA *p_pend_data_tbl,
OS_OBJ_QTY tbl_size)
{
OS_OBJ_QTY i;
OS_OBJ_QTY ctr;
#if OS_CFG_SEM_EN > 0u
OS_SEM *p_sem;
#endif
#if OS_CFG_Q_EN > 0u
OS_Q *p_q;
#endif
for (i = 0u; i < tbl_size; i++) {
if (p_pend_data_tbl->PendObjPtr == (OS_PEND_OBJ *)0) { /* All .PendObjPtr in the table MUST be non NULL */
return (DEF_FALSE);
}
ctr = 0u;
#if OS_CFG_SEM_EN > 0u
p_sem = (OS_SEM *)((void *)p_pend_data_tbl->PendObjPtr); /* All objects to pend on must be of type OS_SEM ... */
if (p_sem->Type == OS_OBJ_TYPE_SEM) {
ctr++;
}
#endif
#if OS_CFG_Q_EN > 0u
p_q = (OS_Q *)((void *)p_pend_data_tbl->PendObjPtr); /* ... or of type OS_Q */
if (p_q->Type == OS_OBJ_TYPE_Q) {
ctr++;
}
#endif
if (ctr == (OS_OBJ_QTY)0) {
return (DEF_FALSE); /* Found at least one invalid object type */
}
p_pend_data_tbl++;
}
return (DEF_TRUE);
}
除了常规参数检查第一个就是调用的这个函数,里面会循环检查你设置好的等待的哪个数组里面的等待对象设置好了没有,如果没设置那么就直接返回。后面就是检查你的设置的里面有几个信号量或者消息队列这个类型,是的一次的话就++一次,所以你走到最后一个if的时候你的ctr肯定不为0,因为你设置的需要等待的多个内核对象肯定是会满足上面两个if使得ctr++几次。返回你得定义正确。
然后就调用这个
nbr_obj_rdy = OS_PendMultiGetRdy(p_pend_data_tbl, /* --------- SEE IF OBJECT(s) HAVE BEEN POSTED ---------- */
tbl_size);
//--------------------------------------------------------------------------------------
OS_OBJ_QTY OS_PendMultiGetRdy (OS_PEND_DATA *p_pend_data_tbl,
OS_OBJ_QTY tbl_size)
{
OS_OBJ_QTY i;
OS_OBJ_QTY nbr_obj_rdy;
#if OS_CFG_Q_EN > 0u
OS_ERR err;
OS_MSG_SIZE msg_size;
OS_Q *p_q;
void *p_void;
CPU_TS ts;
#endif
#if OS_CFG_SEM_EN > 0u
OS_SEM *p_sem;
#endif
nbr_obj_rdy = (OS_OBJ_QTY)0;
for (i = 0u; i < tbl_size; i++) {
p_pend_data_tbl->RdyObjPtr = (void *)0; /* Clear all fields */
p_pend_data_tbl->RdyMsgPtr = (void *)0;
p_pend_data_tbl->RdyMsgSize = (OS_MSG_SIZE )0;
p_pend_data_tbl->RdyTS = (CPU_TS )0;
p_pend_data_tbl->NextPtr = (OS_PEND_DATA *)0;
p_pend_data_tbl->PrevPtr = (OS_PEND_DATA *)0;
p_pend_data_tbl->TCBPtr = (OS_TCB *)0;
#if OS_CFG_Q_EN > 0u
p_q = (OS_Q *)((void *)p_pend_data_tbl->PendObjPtr); /* Assume we are pointing to a message queue object */
if (p_q->Type == OS_OBJ_TYPE_Q) { /* Is it a message queue? */
p_void = OS_MsgQGet(&p_q->MsgQ, /* Yes, Any message waiting in the message queue? */
&msg_size,
&ts,
&err);
if (err == OS_ERR_NONE) {
p_pend_data_tbl->RdyObjPtr = p_pend_data_tbl->PendObjPtr;
p_pend_data_tbl->RdyMsgPtr = p_void; /* Yes, save the message received */
p_pend_data_tbl->RdyMsgSize = msg_size;
p_pend_data_tbl->RdyTS = ts;
nbr_obj_rdy++;
}
}
#endif
#if OS_CFG_SEM_EN > 0u
p_sem = (OS_SEM *)((void *)p_pend_data_tbl->PendObjPtr); /* Assume we are pointing to a semaphore object */
if (p_sem->Type == OS_OBJ_TYPE_SEM) { /* Is it a semaphore? */
if (p_sem->Ctr > 0u) { /* Yes, Semaphore has been signaled? */
p_sem->Ctr--; /* Yes, caller may proceed */
p_pend_data_tbl->RdyObjPtr = p_pend_data_tbl->PendObjPtr;
p_pend_data_tbl->RdyTS = p_sem->TS;
nbr_obj_rdy++;
}
}
#endif
p_pend_data_tbl++;
}
return (nbr_obj_rdy);
}
这里的话可以大致分为三部,设置初始值0,获取是否是消息队列是的话,填充,获取是否是信号量,是的话填充,nbr_obj_rdy这个变量就代表你获取到了多少个需要等待的内核对象。
在就是利用刚才的返回值再次判断,你是否是获取到了内核对象,此时就分为两种
1、获取到了,这个很简单就直接返回,函数结束就行了
if (nbr_obj_rdy > (OS_OBJ_QTY)0) {
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
return ((OS_OBJ_QTY)nbr_obj_rdy);
}
2、没获取到,此时又要看你是阻塞还是非阻塞
非阻塞:退出返回0
阻塞:调用OS_PendMultiWait,解释在下面
if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */
return ((OS_OBJ_QTY)0);
} else {
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_SCHED_LOCKED;
return ((OS_OBJ_QTY)0);
}
}
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
/* ------ NO OBJECT READY, PEND ON MULTIPLE OBJECTS ----- */
OS_PendMultiWait(p_pend_data_tbl, /* Suspend task until object posted or timeout occurs */
tbl_size,
timeout);
OS_CRITICAL_EXIT_NO_SCHED();
OS_PendMultiWait(p_pend_data_tbl, /* Suspend task until object posted or timeout occurs */
tbl_size,
timeout);
//------------------------------------------------------------------------------------
void OS_PendMultiWait (OS_PEND_DATA *p_pend_data_tbl,
OS_OBJ_QTY tbl_size,
OS_TICK timeout)
{
OS_OBJ_QTY i;
OS_PEND_LIST *p_pend_list;
#if OS_CFG_Q_EN > 0u
OS_Q *p_q;
#endif
#if OS_CFG_SEM_EN > 0u
OS_SEM *p_sem;
#endif
OSTCBCurPtr->PendOn = OS_TASK_PEND_ON_MULTI; /* Resource not available, wait until it is */
OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK;
OSTCBCurPtr->PendDataTblEntries = tbl_size;
OSTCBCurPtr->PendDataTblPtr = p_pend_data_tbl;
OS_TaskBlock(OSTCBCurPtr, /* Block the task waiting for object to be posted ... */
timeout); /* ... but with a timeout if not */
for (i = 0u; i < tbl_size; i++) {
p_pend_data_tbl->TCBPtr = OSTCBCurPtr; /* Every entry points back to the TCB of the task */
#if OS_CFG_SEM_EN > 0u
p_sem = (OS_SEM *)((void *)p_pend_data_tbl->PendObjPtr);
if (p_sem->Type == OS_OBJ_TYPE_SEM) {
p_pend_list = &p_sem->PendList;
OS_PendListInsertPrio(p_pend_list,
p_pend_data_tbl);
}
#endif
#if OS_CFG_Q_EN > 0u
p_q = (OS_Q *)((void *)p_pend_data_tbl->PendObjPtr);
if (p_q->Type == OS_OBJ_TYPE_Q) {
p_pend_list = &p_q->PendList;
OS_PendListInsertPrio(p_pend_list,
p_pend_data_tbl);
}
#endif
p_pend_data_tbl++;
}
}
这里鸡是上面说的哪个函数,里面就是把当前需要挂起等待的任务状态保存好(等待多个内核对象,等待的数目,主动挂起)有超时就添加到时钟基准列表,从就绪列表中移除,从就绪列表中移除出去。后续就看,你任务等待的那些内核对象,分别把他们都插入到对应的等待列表中去(指针自增循环)。
3、任务进行调度,这里就是如果等到了任意一个就会返回到这里继续运行,然后整个函数返回一个1,然后函数结束。
OSSched(); /* Find next highest priority task ready */
CPU_CRITICAL_ENTER();
switch (OSTCBCurPtr->PendStatus) {
case OS_STATUS_PEND_OK: /* We got one of the objects posted to */
*p_err = OS_ERR_NONE;
break;
case OS_STATUS_PEND_ABORT: /* Indicate that the multi-pend was aborted */
*p_err = OS_ERR_PEND_ABORT;
break;
case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */
*p_err = OS_ERR_TIMEOUT;
break;
case OS_STATUS_PEND_DEL: /* Indicate that an object pended on has been deleted */
*p_err = OS_ERR_OBJ_DEL;
break;
default:
*p_err = OS_ERR_STATUS_INVALID;
break;
}
OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK;
CPU_CRITICAL_EXIT();
return ((OS_OBJ_QTY)1);
因篇幅问题不能全部显示,请点此查看更多更全内容