ucos2 OSEventPendMulti 详解

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);

}


版权声明:本文为renhao19891216原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。