ucos2 OSEventPendMulti 详解
这个函数的作用: 等待多个事件的挂起
INT16U OSEventPendMulti (OS_EVENT **pevents_pend, OS_EVENT **pevents_rdy, void **pmsgs_rdy, INT16U timeout, INT8U *perr)
{
OS_EVENT **pevents; //定义变量用来存放传进来的 pevents_pend
OS_EVENT *pevent;
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
OS_Q pq;
#endif
BOOLEAN events_rdy;
INT16U events_rdy_nbr;
INT8U events_stat;
#if (OS_CRITICAL_METHOD == 3) / Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
#if (OS_ARG_CHK_EN > 0)
if (perr == (INT8U )0) { / Validate ‘perr’ */
return (0);
}
if (pevents_pend == (OS_EVENT *)0) { / Validate ‘pevents_pend’ */
*perr = OS_ERR_PEVENT_NULL;
return (0);
}
if (pevents_rdy == (OS_EVENT *)0) { / Validate ‘pevents_rdy’ */
*perr = OS_ERR_PEVENT_NULL;
return (0);
}
if (pmsgs_rdy == (void *)0) { / Validate ‘pmsgs_rdy’ */
*perr = OS_ERR_PEVENT_NULL;
return (0);
}
#endif
//从这里开始正题来了
第一段
*pevents_rdy = (OS_EVENT *)0; /* Init array to NULL in case of errors */
pevents = pevents_pend;
pevent = *pevents;
== 第一次遍历所有的event 检查传进来的event是不是都合法 如果中间出现了信号量 、消息队列、邮箱以外的事件 程序就退出==
while (pevent != (OS_EVENT *)0)
{
switch (pevent->OSEventType)
{
#if (OS_SEM_EN > 0)
case OS_EVENT_TYPE_SEM:
break;
#endif
#if (OS_MBOX_EN > 0)
case OS_EVENT_TYPE_MBOX:
break;
#endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
case OS_EVENT_TYPE_Q:
break;
#endif
case OS_EVENT_TYPE_MUTEX:
case OS_EVENT_TYPE_FLAG:
default:
*perr = OS_ERR_EVENT_TYPE;
return (0);
}
pevents++;
pevent = *pevents;
}
if (OSIntNesting > 0) { /* 判断是不是在中断里 */
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
return (0);
}
if (OSLockNesting > 0) { /* 判断是不是在lock里. */
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
return (0);
}
第二段
/*$PAGE*/
OS_ENTER_CRITICAL();
events_rdy = OS_FALSE;
events_rdy_nbr = 0;
events_stat = OS_STAT_RDY;
pevents = pevents_pend;
pevent = *pevents;
==第二次遍历 开始响应3种事件,如果没有条件响应 则在events_stat 中标记出来==
while (pevent != (OS_EVENT *)0)
{
switch (pevent->OSEventType)
{
#if (OS_SEM_EN > 0)
case OS_EVENT_TYPE_SEM: // 是信号量的话
if (pevent->OSEventCnt > 0) { /* 如果大于零说明资源还可以响应信号量。小于0说明信号已经占满 不能再相应新的信号量 */
pevent->OSEventCnt--; /* 响应一次信号量就得减1 */
*pevents_rdy++ = pevent; /* 在事件就绪表中增加一个就绪的事件 */
events_rdy = OS_TRUE; /* 表示当前有事件处于就绪态*/
*pmsgs_rdy++ = (void *)0; /* 没有消息返回 */
events_rdy_nbr++;
} else {
// 如果不能响应信号量 则状态相应的位置1
events_stat |= OS_STAT_SEM; /* Configure multi-pend for semaphore events */
}
break;
#endif
#if (OS_MBOX_EN > 0)
case OS_EVENT_TYPE_MBOX: //是MBOX
if (pevent->OSEventPtr != (void *)0) { /* If mailbox NOT empty; ... */
/* ... return available message, ... */
*pmsgs_rdy++ = (void *)pevent->OSEventPtr;
pevent->OSEventPtr = (void *)0;
*pevents_rdy++ = pevent; /* ... and return available mailbox event */
events_rdy = OS_TRUE;
events_rdy_nbr++;
} else {
events_stat |= OS_STAT_MBOX; /* Configure multi-pend for mailbox events */
}
break;
#endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
case OS_EVENT_TYPE_Q:
pq = (OS_Q *)pevent->OSEventPtr;
if (pq->OSQEntries > 0) { /* If queue NOT empty; ... */
/* ... return available message, ... */
*pmsgs_rdy++ = (void *)*pq->OSQOut++;
if (pq->OSQOut == pq->OSQEnd) { /* If OUT ptr at queue end, ... */
pq->OSQOut = pq->OSQStart; /* ... wrap to queue start */
}
pq->OSQEntries--; /* Update number of queue entries */
*pevents_rdy++ = pevent; /* ... and return available queue event */
events_rdy = OS_TRUE;
events_rdy_nbr++;
} else {
events_stat |= OS_STAT_Q; /* Configure multi-pend for queue events */
}
break;
#endif
case OS_EVENT_TYPE_MUTEX:
case OS_EVENT_TYPE_FLAG:
default:
OS_EXIT_CRITICAL();
*pevents_rdy = (OS_EVENT *)0; /* NULL terminate return event array */
*perr = OS_ERR_EVENT_TYPE;
return (events_rdy_nbr);
}
pevents++;
pevent = *pevents;
}
第三段
if ( events_rdy == OS_TRUE) { /* Return any events already available */
*pevents_rdy = (OS_EVENT *)0; /* NULL terminate return event array */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (events_rdy_nbr);
}
/*$PAGE*/
/* Otherwise, must wait until any event occurs */
OSTCBCur->OSTCBStat |= events_stat | /* Resource not available, ... */
OS_STAT_MULTI; /* ... pend on multiple events */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
OS_EventTaskWaitMulti(pevents_pend); /* Suspend task until events or timeout occurs */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready */
OS_ENTER_CRITICAL();
switch (OSTCBCur->OSTCBStatPend) { /* Handle event posted, aborted, or timed-out */
case OS_STAT_PEND_OK:
case OS_STAT_PEND_ABORT:
pevent = OSTCBCur->OSTCBEventPtr;
if (pevent != (OS_EVENT *)0) { /* If task event ptr != NULL, ... */
*pevents_rdy++ = pevent; /* ... return available event ... */
*pevents_rdy = (OS_EVENT *)0; /* ... & NULL terminate return event array */
events_rdy_nbr++;
} else { /* Else NO event available, handle as timeout */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_TO;
OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
}
break;
case OS_STAT_PEND_TO: /* If events timed out, ... */
default: /* ... remove task from events' wait lists */
OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
break;
}
switch (OSTCBCur->OSTCBStatPend) {
case OS_STAT_PEND_OK:
switch (pevent->OSEventType) { /* Return event's message */
#if (OS_SEM_EN > 0)
case OS_EVENT_TYPE_SEM:
*pmsgs_rdy++ = (void *)0; /* NO message returned for semaphores */
break;
#endif
#if ((OS_MBOX_EN > 0) || \
((OS_Q_EN > 0) && (OS_MAX_QS > 0)))
case OS_EVENT_TYPE_MBOX:
case OS_EVENT_TYPE_Q:
*pmsgs_rdy++ = (void *)OSTCBCur->OSTCBMsg; /* Return received message */
break;
#endif
case OS_EVENT_TYPE_MUTEX:
case OS_EVENT_TYPE_FLAG:
default:
OS_EXIT_CRITICAL();
*pevents_rdy = (OS_EVENT *)0; /* NULL terminate return event array */
*perr = OS_ERR_EVENT_TYPE;
return (events_rdy_nbr);
}
*perr = OS_ERR_NONE;
break;
case OS_STAT_PEND_ABORT:
*pmsgs_rdy++ = (void *)0; /* NO message returned for abort */
*perr = OS_ERR_PEND_ABORT; /* Indicate that event aborted */
break;
case OS_STAT_PEND_TO:
default:
*pmsgs_rdy++ = (void *)0; /* NO message returned for timeout */
*perr = OS_ERR_TIMEOUT; /* Indicate that events timed out */
break;
}
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 */
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
OSTCBCur->OSTCBMsg = (void *)0; /* Clear task message */
OS_EXIT_CRITICAL();
return (events_rdy_nbr);
}