uC/OS-II內核架構解析(5)---uC/OS-II通信與同步

1. 消息郵箱Mbox

     Mbox用於多任務間單一消息的傳遞,uC/OS-II使用ECB管理Mbox的基本信息,OSEventPtr指向創建Mbox時指定的內存空間。事件的創建由具體的事件管理程序實現。主要包含在C源文件OS_MBOX.C中。

  • OS_EVENT *OSMboxCreate(void *msg);

  • void *OSMboxPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);

  • void *OSMboxAccept(OS_EVENT *pevent);

  • INT8U OSMboxPost(OS_EVENT *pevent, void *msg);

  • INT8U OSMboxPostOpt(OS_EVENT *pevent, void *msg, INT8U opt);

  • OS_EVENT *OSMboxDel(OS_EVENT *pevent, INT8U opt, INT8U *err);

  • INT8U OSMboxQuery(OS_EVENT *pevent, OS_MBOX_DATA *);

2010051115235056.jpg


2010051116115125.jpg

2. 消息隊列msgQ

(1) msgQ基本內容

     msgQ是uC/OS-II任務間通信的機制,可實現多條消息傳遞,即可以同時存儲多條消息。uC/OS-II使用循環隊列管理機制。主要包含在C源文件OS_Q.C中。

     msgQ管理:使用指針數組存儲所有消息的位置;使用QCB標識指針數組中消息的基本信息;使用ECB管理整個msgQ。QCB在編譯時分配空間,即當前系統中可用的msgQ個數是預先設置的,系統運行時不能修改。

2010051115252380.jpg

(2) msgQ全局變量

  • OS_EXT OS_Q *OSQTbl[OS_MAX_QS];   //QCB結構體數組

  • OS_EXT OS_Q *OSQFreeList;                    //空閒QCB頭指針

  • typedef struct os_q{                                //消息隊列控制塊

      struct os_q *OSQPtr;        //用於構建空閒QCB鏈表

      void **OSQStart;              //指向msgQ指針數組的起始位置

      void **OSQEnd;               //指向msgQ指針數組的結束位置

      void **OSQIn;    //指向msgQ指針數組下一個可以插入消息的位置

      void **OSQOut; //指向msgQ指針數組下一個可以讀出消息的位置

      INT16U OSQSize;            //msgQ指針數組的大小

      INT16U OSQEntries;              //msgQ指針數組當前可以讀取的消息個數

             }OS_Q;

2010051116181554.jpg

(3) msgQ管理函數

  • OS_EVENT *OSQCreate(void **start, INT16U size);

  • INT8U OSQPost(OS_EVENT *pevent, void *msg); //發送消息到隊尾

  • INT8U OSQPostFront(OS_EVENT *pevent, void *msg);      //msg至隊首

  • INT8U OSQPostOpt(OS_EVENT *pevent, void *msg, INT8U opt);

  • void *OSQPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);

  • void *OSQAccept(OS_EVENT *pevent, INT8U *err);

  • OS_EVENT *OSQDel(OS_EVENT *pevent, INT8U opt, INT8U *err);

  • INT8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA*);

  • INT8U OSQFlush(OS_EVENT *pevent);

2010051115275215.jpg

(4) msgQ幾個問題

     uC/OS-II中,什麼是事件?事件是uC/OS-II管理任務間同步與通信的機制。

     事件是處理事件的對象感興趣的,能夠感知或捕獲到一種事件狀態的改變。

3. 信號量Sem

     Sem主要用來實現任務間同步及標識某類資源的可用個數,即某個特定資源可供多少任務同時使用。主要包含在C源文件OS_SEM.C中。

  • OS_EVENT *OSSemCreate(INT16U cnt);

  • void OSSemPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);

  • INT16U OSSemAccept(OS_EVENT *pevent);

  • INT8U OSSemPost(OS_EVENT *pevent);

  • OS_EVENT *OSSemDel(OS_EVENT *pevent, INT8U opt, INT8U *err);

  • INT8U OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA*);

  • void OSSemSet(OS_EVENT *pevent, INT16U cnt, INT8U *err);

2010051115304776.jpg

4. 互斥鎖Mutex

(1) Mutex基本原理

     Mutex用來實現對資源的排他性訪問,可能引起優先級反轉。任何任務在佔有某個互斥鎖事件時,都不能阻塞等待其它任何事件,否則會造成死鎖。主要包含在C源文件OS_MUTEX.C中。

     優先級反轉是指,低優先級任務佔有高優先級任務運行所需的資源,而使高優先級不得不等低優先級任務把資源釋放才能執行。

     uC/OS-II使用ECB管理Mutex,其成員變量OSEventCnt:高8位存儲Mutex被使用時提供給任務的prio;低8位在沒有任務佔有Mutex時爲0xFF,否則爲佔有任務的prio。

優先級反轉優先級反轉避免分別如下圖所示:

2010051116135683.jpg


2010051116155026.jpg

(2) 提升/恢復優先級

   a) 提升Mutex擁有者任務的優先級的相關操作:

  • 如果該任務原來處於就緒狀態,則從就緒表中將其刪除;如果該任務正在等待某個事件,則從該事件的任務等待表中將其刪除;

  • 修改擁有Mutex的TCB,將其OSTCBPrio修改爲欲提升的優先級;

  • 如果該任務處於就緒狀態,則將提升的優先級加載到任務就緒表中;如果該任務未就緒且正在等待某個事件,則將提升的優先級添加到該事件的任務等待表中,並修改TCB中OSTCBEventPtr;

  • 修改TCB中與優先級相關的成員變量。

   b) 恢復Mutex擁有任務的優先級的相關操作:

  • 從任務就緒表中刪除提升過的優先級值,修改當前TCB中與優先級相關的所有成員變量;

  • 再次保留提升的優先級值控制塊入口,避免將其分配給其它任務。

(3)Mutex管理函數

  • #define  OS_MUTEX_KEEP_LOWER_8   0x00FF

  • #define  OS_MUTEX_KEEP_UPPER_8   0xFF00

  • #define  OS_MUTEX_AVAILABLE      0x00FF


  • OS_EVENT *OSMutexCreate(INT8U prio, INT8U *err);

  • void OSMutexPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);

  • INT8U OSMutexAccept(OS_EVENT *pevent, INT8U *err);

  • INT8U OSMutexPost(OS_EVENT *pevent);

  • OS_EVENT *OSMutexDel(OS_EVENT*, INT8U opt, INT8U *err);

  • INT8U OSMutexQuery(OS_EVENT*, OS_MUTEX_DATA*);

2010051115332131.jpg

5. 事件組標誌Flag

(1) Flag基本原理

     uC/OS-II提供事件組標誌實現多事件管理。Flag只是使用0/1來表示某個事件是否發生過,而不能直接被用來傳遞數據和消息。可以選擇性地設置一個Flag最多可以管理的任務同步狀態。主要包含在C源文件OS_FLAG.C中。

2010051115362340.jpg

(2) Flag數據結構

  • #define OS_FLAGS_NBITS 8/16/32     //定義OS_FLAGS的位數

  • FCB結構體:

   typedef struct os_flag_grp{

         INT8U OSFlagType;                        //事件類型

         void *OSFlagWaitList;                      //指向等待的任務鏈表

         OS_FLAGS OSFlagFlags;               //信號列表

         INT8U OSFlagName[OS_FLAG_NAME_SIZE];

    }OS_FLAG_GRP;

  • 事件標誌等待鏈表結點

   typedef struct os_flag_node{

         void *OSFlagNodeNext;

         void *OSFlagNodePrev;

         void *OSFlagNodeTCB;

         void *OSFlagNodeFlagGrp;          //指向此任務所等待的事件組標誌

         OS_FLAGS OSFlagNodeFlags;     //等待的事件

         INT8U OSFlagNodeWaitType;       //等待方式

    }OS_FLAG_NODE;

  • OS_EXT OS_FLAG_GRP OSFlagTbl[OS_MAX_FLAGS];

  • OS_EXT OS_FLAG_GRP *OSFlagFreeList;

  • OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags, INT8U *err);

  • OS_FLAGS OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags,

(3) Flag管理函數

  • INT8U wait_type, INT16U timeout, INT8U *err);

  • static void OS_FlagBlock(OS_FLAG_GRP *pgrp,

            OS_FLAG_NODE *pnode,

            OS_FLAGS flags,

            INT8U wait_type,    //掛起任務,

            INT16U timeout);     //直到等待的事件或超時

             類似於:OS_EventTaskWait();

  • void OS_FlagUnlink(OS_FLAG_NODE *pnode);   //等待超時刪除結點

      類似於:OS_EventTO();

  • OS_FLAGS OSFlagAccept(OS_FLAG_GRP *pgrp,

            OS_FLAGS flags,

            INT8U wait_type,

            INT8U *err);

  • OS_FLAGS OSFlagPost(OS_FLAG_GRP *pgrp,

            OS_FLAGS flags,

            INT8U opt,

            INT8U *err);

  • static BOOLEAN OS_FLAGTaskRdy(OS_FLAG_NODE *pnode,

            OS_FLAGS flags_rdy);

  • OS_FLAG_GRP *OSFlagDel(OS_FLAG_GRP*, INT8U opt, INT8U *err);

  • OS_FLAGS OSFlagPendGetFlagsRdy(void);    //獲取任務就緒標誌

  • OS_FLAGS OSFlagQuery(OS_FLAG_GRP*, INT8U *err);

  • INT8U OSFlagNameGet(OS_FLAG_GRP*, INT8U *pname, INT8U *err);

  • void OSFlagNameSet(OS_FLAG_GRP*, INT8U *pname, INT8U *err);

2010051115415193.jpg

6. Task就緒狀態判斷???

   a) OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX != 0

       如:函數OSMutexPend()

   b) (ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY

       如:函數OSTimeTick()

   c) ptcb->OSTCBStat == OS_STAT_RDY

       如:函數OS_EventTaskRdy()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章