<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        ucos OSEventPendMulti 函數解析

        作者:佚名   來源:本站原創   點擊數:  更新時間:2014年04月27日   【字體:

         這個函數是請求信號量,郵箱,消息隊列的,但是對互斥信號量和標志不起作用。

        #if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u))
        INT16U  OSEventPendMulti (OS_EVENT  **pevents_pend,//掛起的事件組(需要請求資源)
                                  OS_EVENT  **pevents_rdy, //就緒的事件組
                                  void      **pmsgs_rdy,   //保存請求中返回的信息
                                  INT32U      timeout,     //請求資源的時間,如果超時任務進入休眠態
                                  INT8U      *perr)        
        {
            OS_EVENT  **pevents;
            OS_EVENT   *pevent;
        #if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))
            OS_Q       *pq;             //如果使用隊列且最大隊列控制塊數大于0則申請一個隊列控制塊指針
        #endif
            BOOLEAN     events_rdy;     //是否有準備好的事件標志
            INT16U      events_rdy_nbr; //準備好的事件數
            INT8U       events_stat;    //事件狀態
        #if (OS_CRITICAL_METHOD == 3u)  
            OS_CPU_SR   cpu_sr = 0u;
        #endif
         
        #ifdef OS_SAFETY_CRITICAL
            if (perr == (INT8U *)0) {
                OS_SAFETY_CRITICAL_EXCEPTION();
            }
        #endif
        //驗證各個參數的有效性
        #if (OS_ARG_CHK_EN > 0u)
            if (pevents_pend == (OS_EVENT **)0) {      
               *perr =  OS_ERR_PEVENT_NULL;
                return (0u);
            }
            if (*pevents_pend  == (OS_EVENT *)0) {    
               *perr =  OS_ERR_PEVENT_NULL;
                return (0u);
            }
            if (pevents_rdy  == (OS_EVENT **)0) {      
               *perr =  OS_ERR_PEVENT_NULL;
                return (0u);
            }
            if (pmsgs_rdy == (void **)0) {            
               *perr =  OS_ERR_PEVENT_NULL;
                return (0u);
            }
        #endif
        //初始化指向就緒事件數組的指針為NULL
           *pevents_rdy = (OS_EVENT *)0;              
        //pevents指向掛起等待的事件組,已經處于就緒態的事件組是不需要再判斷的,pevent指向該事件組中的事件.
            pevents     =  pevents_pend;
            pevent      = *pevents;
        //對事件組中的所有事件進行類型檢查
            while  (pevent != (OS_EVENT *)0) {
                switch (pevent->OSEventType) {        
        #if (OS_SEM_EN  > 0u)
                    case OS_EVENT_TYPE_SEM:
                         break;
        #endif
        #if (OS_MBOX_EN > 0u)
                    case OS_EVENT_TYPE_MBOX:
                         break;
        #endif
        #if ((OS_Q_EN   > 0u) && (OS_MAX_QS > 0u))
                    case OS_EVENT_TYPE_Q:
                         break;
        #endif
         
                    case OS_EVENT_TYPE_MUTEX:
                    case OS_EVENT_TYPE_FLAG:
                    default:
                        *perr = OS_ERR_EVENT_TYPE;
                         return (0u);
                }
                pevents++;        //即數組地址+1
                pevent = *pevents;//指向下一個元素
            }
        //不能在中斷程序中調用
            if (OSIntNesting  > 0u) {                  
               *perr =  OS_ERR_PEND_ISR;                
                return (0u);
            }
        //任務被鎖住也是不能掛起的
            if (OSLockNesting > 0u) {                  
               *perr =  OS_ERR_PEND_LOCKED;            
                return (0u);
            }
         
            OS_ENTER_CRITICAL();                 //進入中斷沿
            events_rdy     =  OS_FALSE;          //事件就緒標志初始化為0
            events_rdy_nbr =  0u;                //就緒事件數初始化為0
            events_stat    =  OS_STAT_RDY;       //事件狀態初始化為就緒態
            pevents        =  pevents_pend;      //pevents指向掛起等待的事件組 pevent指向事件組中的事件
            pevent         = *pevents;
            while (pevent != (OS_EVENT *)0) {    //當最后一個元素值為(OS_EVENT *)0時等待事件組都判斷完了
                switch (pevent->OSEventType) {   //對事件組中請求特定資源的事件做特定處理
        #if (OS_SEM_EN > 0u)                       
                    case OS_EVENT_TYPE_SEM:      //信號量事件,信號量大于0說明資源是可用的
                         if (pevent->OSEventCnt > 0u) {
                             pevent->OSEventCnt--;      
            //請求得到滿足,可用的信號量數就減少了所以要--
                            *pevents_rdy++ =  pevent;  
            //這個事件進入就緒事件表
                              events_rdy   =  OS_TRUE;
            //標志一下有事件就緒了
                            *pmsgs_rdy++   = (void *)0;
            //信號量沒有返回消息
                              events_rdy_nbr++;
            //就緒的事件數加1
                         } else {
                              events_stat |=  OS_STAT_SEM;
            //請求失敗則標記為事件組等待信號量
                         }
                         break;
        #endif
         
        #if (OS_MBOX_EN > 0u)
                    case OS_EVENT_TYPE_MBOX://是郵箱事件如果郵箱有東西則請求得到滿足
                         if (pevent->OSEventPtr != (void *)0) {                                      *pmsgs_rdy++=(void *)pevent->OSEventPtr;
             //把郵箱的消息地址保存在message_ready數組中
                             pevent->OSEventPtr  = (void *)0;
             //請求了一個郵箱郵箱就由非空狀態變空
                             *pevents_rdy++=pevent;
                             //這個事件進入就緒態
                              events_rdy=OS_TRUE;        
                             //標志一下有事件就緒了
                              events_rdy_nbr++;
                             //準備好的事件數加1
                         } else {
                              events_stat |= OS_STAT_MBOX;
                             //請求郵箱失敗標記事件組等待郵箱
                         }
                         break;
        #endif
         
        #if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))
                    case OS_EVENT_TYPE_Q:                //如果是隊列事件
                         pq = (OS_Q *)pevent->OSEventPtr;//pq指向隊列事件指針
                         if (pq->OSQEntries > 0u) {      //如果隊列非空                          
                         *pmsgs_rdy++ = (void *)*pq->OSQOut++;
                                 //把隊列的消息保存在pmsgs_rdy的數組中
                             if (pq->OSQOut == pq->OSQEnd) {
                                 pq->OSQOut = pq->OSQStart;
                             }   //隊列的鏈表要把首尾連接起來
                             pq->OSQEntries--; 
                             //請求了一個隊列隊列中消息就減少了(隊列是鏈表,其中一塊少了即入口少了)
                            *pevents_rdy++ = pevent;      
                             //請求得到允許事件進入就緒態                    
                             events_rdy   = OS_TRUE;          //標志一下有事件就緒了  
                              events_rdy_nbr++;               //就緒事件數加1
                         } else {
                              events_stat |= OS_STAT_Q;    }
                             //請求隊列未得到允許則標志事件組狀態為等待隊列                 
                         break;
        #endif
         
                    case OS_EVENT_TYPE_MUTEX:
                    case OS_EVENT_TYPE_FLAG:
                    //對互斥信號量事件和標志事件則不做處理
                    default:
                    //如果都不是這些事件類型則退出中斷沿并返回事件類型錯誤
                         OS_EXIT_CRITICAL();
                        *pevents_rdy = (OS_EVENT *)0;//這里用這個(OS_EVENT *)0返回空的消息
                    //因為是先保存再加所以出現錯誤不會有后續判斷這里就不用++
                        *perr=  OS_ERR_EVENT_TYPE;
                         return (events_rdy_nbr);    //返回就緒的事件數
                }
                pevents++;
                pevent = *pevents;                              
                //對事件組中的每一個事件做判斷
            }
         
            if ( events_rdy == OS_TRUE) {    
               *pevents_rdy = (OS_EVENT *)0;  
               //所有的事件都判斷完了補上一個 (OS_EVENT *)0的結束標志
                OS_EXIT_CRITICAL();
               *perr  =  OS_ERR_NONE;
                return (events_rdy_nbr);    //返回事件的就緒數(調用這個函數的任務繼續運行)
            }
               //如果沒有事件就緒即所有請求都失敗則掛起調用該函數的函數  
            OSTCBCur->OSTCBStat     |= events_stat  | OS_STAT_MULTI;
               //標記當前事件控制塊中的事件狀態為等待資源而且是等待多個資源
            OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
               //配置當前事件控制塊中的事件狀態標志為等待完成,因為這個事件即將被切換掉,進入掛起態
            OSTCBCur->OSTCBDly       = timeout;        
               //設置該任務掛起等待的時間為timeout時間,超時任務就被切換掉。
            OS_EventTaskWaitMulti(pevents_pend);      
            //暫停任務直到出現新的事件呼叫或者掛起時間到
            OS_EXIT_CRITICAL();
            //退出中斷沿
            OS_Sched();                                
            //如果當前任務不處于就緒態將進行任務調度將優先級最高的任務調入運行態
            OS_ENTER_CRITICAL();
            //進入中斷沿
            //對當前最高優先級的事件進行狀態判斷(下一個任務或還是之前的任務)
            switch (OSTCBCur->OSTCBStatPend) {        
                case OS_STAT_PEND_OK:                  //等待完成和等待終止都進行相同處理
                case OS_STAT_PEND_ABORT:
                     pevent = OSTCBCur->OSTCBEventPtr;
                     if (pevent != (OS_EVENT *)0) {    
                        //有任務就緒了
                        *pevents_rdy++ =  pevent;      
                        //把這個任務的地址存儲到pevents_rdy數組中
                        *pevents_rdy   = (OS_EVENT *)0;
                        //最后一個標志為結束符
                          events_rdy_nbr++;
                        //就緒事件數加1
                     } else {                            
                         OSTCBCur->OSTCBStatPend = OS_STAT_PEND_TO;
                        //如果沒有任務就緒標志為超時處理,這里不明白########
                         OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
                        //解除暫停將任務從等待列表中刪除
                     }
                     break;
         
                case OS_STAT_PEND_TO:                  
                default:                              
                     OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);//掛起時間到將任務從等待列表中刪除
                     break;
            }
            //這個switch是用來消息傳遞的  
            switch (OSTCBCur->OSTCBStatPend) {
                case OS_STAT_PEND_OK:                   //掛起完成也標志該事件又處在就緒態了
                     switch (pevent->OSEventType) {    
        #if (OS_SEM_EN > 0u)
                         case OS_EVENT_TYPE_SEM:
                             *pmsgs_rdy++ = (void *)0;  
                            //信號量沒有返回消息
                              break;
        #endif
         
        #if ((OS_MBOX_EN > 0u) ||((OS_Q_EN    > 0u) && (OS_MAX_QS > 0u)))
                         case OS_EVENT_TYPE_MBOX:
                         case OS_EVENT_TYPE_Q:
                             *pmsgs_rdy++ = (void *)OSTCBCur->OSTCBMsg;
                              break;                   //把郵箱和隊列中的消息保存在pmsgs_rdy數組中
        #endif
         
                         case OS_EVENT_TYPE_MUTEX:
                         case OS_EVENT_TYPE_FLAG:
                         default:
                              OS_EXIT_CRITICAL();
                             *pevents_rdy = (OS_EVENT *)0;
                             *perr        =  OS_ERR_EVENT_TYPE;
                              return (events_rdy_nbr);
                     }
                    *perr = OS_ERR_NONE;
                     break;
         
                case OS_STAT_PEND_ABORT:              //等待終止返回空消息
                    *pmsgs_rdy++ = (void *)0;        
                    *perr        =  OS_ERR_PEND_ABORT;
                     break;
         
                case OS_STAT_PEND_TO:                 //等待超時也返回空消息                  
                default:
                    *pmsgs_rdy++ = (void *)0;          
                    *perr        =  OS_ERR_TIMEOUT;    
                     break;
            }
         
            OSTCBCur->OSTCBStat          =  OS_STAT_RDY;
        //事件標記為就緒態
            OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;
        //清除掛起標志
            OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;
            OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
        #if ((OS_MBOX_EN > 0u) ||((OS_Q_EN    > 0u) && (OS_MAX_QS > 0u)))
            OSTCBCur->OSTCBMsg      = (void      *)0;  
        #endif
            OS_EXIT_CRITICAL();
         
            return (events_rdy_nbr);
        }
        #endif
        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮