1. 程式人生 > >µC/OS-II核心任務排程模組的擴充套件

µC/OS-II核心任務排程模組的擴充套件

 

摘 要:µC/OS-II是一個實時作業系統核心,支援64種不同優先順序的任務。以簡單實用為原則,借用核心中的兩個優先順序任務,充當時鐘源和輪詢引擎,讓同級任務在最低優先順序任務下輪流執行。這在不失實時性的前提下,讓核心支援多達192個同級任務,極大地擴充套件了µC/OS-II的靈活性和應用範圍。

關鍵字: µC/OS-II;同級任務;時間片輪詢排程;實時性;擴充套件

中圖分類號: TP316    文獻標識碼: A

Expansion on task scheduling module of µC/OS-II kernel

Abstract : µC/OS-II is a real-time operating system kernel, supporting tasks in 64 different priorities. With the principle of simple and practical, it borrows two priority tasks in the kernel as the clock source and the polling engine, so that tasks with the same priority work under the lowest priority in turns. The method allows the kernel to support up to 192 tasks in the same priority  without losing the real-time, which greatly expands the flexibility and range of applications of µC/OS-II .

Key words : µC/OS-II ; Same priority task ; Round-Robin algorithm scheduling ;Real-time ; Expansion

0    引言

物聯網時代來臨,嵌入式系統用途愈加廣泛。嵌入式系統一個極為核心的技術就是嵌入式作業系統。目前常用的嵌入式作業系統有µClinux、µC/OS-II、WinCE、VxWorks等。其中µC/OS-II以其實時性強、原始碼開放、高效而小巧等優點得到了比較廣泛的應用。

µC/OS-II是一個具有基本功能的作業系統核心,包括基於優先順序的可剝奪式任務排程和簡單的記憶體管理等。µC/OS-II核心支援64種不同優先順序的任務,不支援同級任務,不支援時間片輪詢任務排程[1]

。這樣的系統完全為硬實時環境而設計,在某些實際應用中侷限了系統的靈活性和應用範圍,例如多點的溫度或氣壓資料採集,這些任務往往需要同優先順序進行排程。

給µC/OS-II新增同級任務排程,核心研究者提出了各種不同的方法。文獻[2]中提出一種將8個優先順序任務轉換為相同優先順序任務,並基於時間片輪詢排程的方法;文獻[3]中提出一種將任務排程在優先順序搶佔與時間片輪詢之間輪流選用的方法。文獻[4]中提出一種將單一優先順序任務擴充套件為優先順序任務連結串列,從而達到新增同級任務的方法。上述方法從不同的技術角度為µC/OS-II添加了同級任務排程,儘管有的方法從理論上講符合邏輯,但是實際操作較為複雜,方案實用性較差、實時性難以保證。在不失實時性,同時儘可能少改動原有核心架構的前提下,提出一種佔用2個優先順序任務,為系統擴展出最多192個同級任務基於時間片輪詢排程的方案。

1    思路與模型

在新增基於時間片輪詢的同級任務排程時,模仿了µC/OS-II核心原有資料結構。

1.1 總體思路

設計的總體思路是:模仿優先順序任務連結串列,建立一個同級任務連結串列。建立兩個優先順序任務A和B,且B=A+1。A以時間片為單位週期性的進入等待或執行,從而週期性的中斷B。 B每次執行總是從同級任務連結串列取一個處於就緒態的同級任務,然後跳入同級任務執行。當沒有比A更高優先順序的任務時,同級任務以時間片為單位輪流在B下執行。B每次中斷,總是將斷點儲存到當前執行的同級任務堆疊。B下次被核心排程執行,不會返回同級任務,而是重新進入B的任務,開始新一輪的輪詢。

1.2  時鐘源

時間片輪詢排程演算法,首先面臨的問題是時鐘來源。可以利用原有系統的功能,模擬時鐘源。建立一個優先順序任務A(下面用A標識此任務),利用系統延時函式OSTimeDly(),週期性的讓A進入等待狀態。建立一個優先順序任務B(下面用B標識此任務,B=A+1),B的作用是輪詢排程同級任務。每當A進入等待狀態,如果沒有比A更高優先順序的任務,核心會排程B執行。一旦A等待結束進入就緒態,核心會中斷B,由此B週期性地執行或中斷,則自發為B提供了時鐘源。由於A和B是核心中的兩個優先順序任務,它們服從核心排程,所以不會破壞核心的實時性。

1.3  構造同級任務

µC/OS-II以一個位元組存貯任務優先順序,使用64種不同的優先順序狀態。一個位元組可以表達256種狀態,剩餘的192種狀態可用來標識同級任務。同級任務的狀態標識從64開始,256為最大。192個同級任務仍然用優先順序數字標識,但是這裡的優先順序數字不再代表同級任務的優先級別,僅僅作為區分同級任務的編號。

同級任務的資料結構模仿優先順序任務。仿照優先順序任務連結串列建立同級任務連結串列,同級任務的優先順序編號從64開始。在呼叫OSTaskCreate()等函式建立任務時,如果任務優先順序是介於64到256之間,說明任務是同級任務,需要新增到同級任務連結串列中。UserTbl[]陣列表示同級任務控制塊陣列。每當建立新的同級任務時,總是將空的任務連結串列頭UserFreeList指向的任務控制塊分配給該任務。在給任務控制塊中的各成員賦值後,就按任務控制塊連結串列的頭指標UserList將其加入到任務控制塊連結串列中[5]。UserCur指向連結串列中即將排程的同級任務。具體資料結構如下圖所示。

圖1:同級任務控制塊資料結構

1.4  輪詢引擎

1.2中已經說明,“同級任務輪詢引擎”是系統的一個優先順序任務,用B標識。當B第一次進入任務程式碼時,會將當前執行位置儲存到一個全域性變數(在C語言中可通過setjmp()來完成),便於在其它地方可以跳回此處。此後,B取得同級任務連結串列中UserCur指向的任務控制塊,檢查UserCur指向的任務是否處於就緒狀態,是則跳入此同級任務去執行,否則調整UserCur指向下一個控制塊。

UserCur指向的同級任務執行一個時間片後,A從等待態進入就緒態,進而中斷B。B立即將當前的執行斷點儲存到UserCur指向的同級任務堆疊中。當下一次B排程執行時,B會跳回第一次執行時設定的全域性變數斷點處(在C語言中可通過longjmp()來完成),開始新一輪的輪詢。

A不僅提供了B的時鐘源,還負責更新UserCur。每次A從等待態進入執行態時,將UserCur重新指向下一個節點,由此使得B每次輪詢時都是從新的同級任務開始。這裡有必要設定一個全域性變數UserCount,表示同級任務連結串列中處於就緒態任務的個數,如果其值為0,A不需要更新UserCur,B也會進入等待狀態,從而不浪費系統資源。輪詢引擎執行過程如下圖。

圖2: 同級任務排程流程模型

2    同級任務排程的實現

所用原始碼是µC/OS-II 2.52,以下所有函式及變數均基於此。

2.1  時鐘節拍

核心中每發生一次時鐘中斷,均會呼叫OSTimeTick()。OSTimeTick()負責更新任務的延時節拍,將延時結束的任務更新到就緒表,新增對同級任務的處理虛擬碼如下。

ptcb = OSTCBList;

while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {

//原系統程式碼不做任何修改 }

//新增對同級任務的處理

ptcb = UserList;

while(ptcb != 0){

OS_ENTER_CRITICAL();

if (ptcb->OSTCBDly != 0) {

if (--ptcb->OSTCBDly == 0) {

if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {

更新B到就緒表; //有同級任務就緒,將B 新增到就緒表                   

UserCount ++ ;//同級任務就緒個數更新

}else{ptcb->OSTCBDly= 1; }

}}

ptcb=ptcb->OSTCBNext;

OS_EXIT_CRITICAL();

}

核心中並沒有同級任務的就緒表,當有同級任務就緒時,則使輪詢引擎B進入就緒態。B一旦獲得執行時間,同級任務則按時間片輪詢規則得到執行。

2.2  任務延時

核心中的任務空閒時,需呼叫延時函式進入等待狀態,以釋放系統資源。常用的延時函式是OSTimeDly(),其它延時函式也是借用此函式完成[7]。同級任務是借用輪詢引擎B得以執行,當前執行的同級任務進入等待態後,不能簡單的讓B也進入等待,而是進行一次排程,讓其它處於就緒態的同級任務有機會繼續在B下執行。OSTimeDly()新增對同級任務的處理虛擬碼如下。

if (ticks>0) {

OS_ENTER_CRITICAL();

if(OSTCBCur->OSTCBPrio == B ){ //如果是輪詢引擎B

UserCur->OSTCBDly = ticks; // UserCur指向的同級任務延時

if(--UserCount >0){ //還有其他同級任務

OS_EXIT_CRITICAL();

OS_Sched();//主動排程一次

return;

}}

//後面是原系統程式碼,不做任何修改

}

當沒有同級任務處於就緒態時,B 會呼叫原來程式碼,進入等待狀態,不會浪費系統資源。

2.3  中斷儲存和排程規則

為了完成同級任務基於時間片輪詢排程,需對系統中有關中斷儲存和排程規則進行修改。µC/OS-II 2.52原始碼中,OS_Sched() 與OSCtxSw()與任務排程相關, OSTickISR() 、OSIntCtxSw()、OSIntExit()與中斷相關。完成任務切換或中斷跳轉的函式是OSCtxSw()和OSIntCtxSw()。

OS_Sched()與OSIntExit()作用類似,不同的是後者呼叫之前斷點已經自動儲存過。輪詢引擎B每次中斷需要將斷點儲存到UserCur指向的同級任務堆疊,下次排程執行不是返回上一個同級任務,而是返回第一次設定的全域性變數斷點處,開始新一輪的輪詢。在每次任務切換與B有關時,必須主動儲存同級任務斷點,修改OS_Sched()虛擬碼如下。

if (OSPrioHighRdy != OSPrioCur) {

//原系統程式碼不加修改}

if(OSPrioHighRdy==B){ //最高就緒任務是B

OS_TASK_SW();  //主動切換任務, OS_TASK_SW() 內部會儲存同級任務斷點       

}//原系統程式碼不加修改

對於OSIntExit()則不需修改,因為此函式呼叫之前斷點已經自動儲存過。

OSTickISR()、OSCtxSw()、OSIntCtxSw()三個函式位於Os_cpu_a.asm中,是用匯編語言編寫,需要新增相應的判斷和跳轉程式碼。對於判斷兩個任務的優先順序是否一樣,需要比較任務控制塊中的OSTCBPrio變數。由於此變數在OS_TCB結構的尾部,不便於定址,可將它改到OS_TCB結構中的第二個位置,即位於OSTCBStkPtr變數之後。(OSTCBStkPtr也要方便定址,故其在第一[1])。這三個函式,在原有中斷儲存和任務切換程式碼上,需要服從以下邏輯規則:

當被中斷的任務是輪詢引擎B時,需將斷點儲存到UserCur指向的同級任務堆疊中,而不是任務B自身的堆疊,新增彙編虛擬碼如下:

LES  BX ,DWORD PTR DS:_OSTCBCur ; 取當前執行的優先順序任務

CMP  BYTE PTR ES:[BX+4], #B ; 判斷當前執行的優先順序任務是否為B

JNE    _OLD ; 不是B ,跳到原有程式碼

MOV   AX, SEG(_UserCur) ; 取UserCur指向的同級任務

MOV   DS,AX ;

LES    BX,DWORD PTR DS:_ UserCur ;

MOV   ES:[BX+2], SS ; 儲存斷點到UserCur指向的同級任務

MOV   ES:[BX+0], SP ;

JMP    _NEW ; 儲存斷點後,跳過原有儲存斷點語句

當即將排程執行的優先順序任務是B時,需要返回到第一次B執行時設定的全域性變數斷點處,而不是上一個同級任務,新增彙編虛擬碼如下:

LES  BX ,DWORD PTR DS:_OSTCBHighRdy ; 取就緒的最高優先順序任務

CMP  BYTE PTR ES:[BX+4],#B; 判斷就緒的最高優先順序任務是否為B

JNE    _OLD; 不是B ,跳到原有程式碼

CALL FAR PTR  _OSLONGJMP; 是B ,返回第一次設定的全域性變數斷點處

3  實驗

為了檢驗改造後的µC/OS-II,需要把µC/OS-II移植到合適的處理器上執行。這裡選擇Intel的x86系列CPU。硬體平臺包括 Intel Pentium Dual-Core CPU 2.30GHz ,2GB 記憶體。作業系統平臺採用Windows Xp ,編譯器採用 Borland C++ V4.5 ,原始碼為µC/OS-II 2.52。移植程式碼針對x86的真實模式,使用BC4.5在大模式下編譯和連結。

讓A的優先順序為58,B 的優先順序為59 ,如此一來,除去系統保留優先順序外,同級任務輪流執行在最低優先順序下,其他優先順序任務都可以中斷B的執行,從而不干擾任何優先順序任務的實時性。實驗中除A、B外,另建立了5個優先順序任務,同時建立了優先順序編號從64到73共十個同級任務,任務堆疊TASK_STK_SIZE均設為512,時間片單位為100ms。任務的工作是呼叫PC_DispChar()在螢幕不同行上打印出不同的字元,優先順序任務分別列印0 ~ 4 ,同級任務分別列印A ~ G。經測試,系統工作狀態良好,結果如下所示。

圖3:實驗執行結果(略)

4  結論

本文的出發點在於:從簡單實用的角度為µC/OS-II擴展出基於時間片輪詢排程的同級任務。創新點在於:在儘量少改動核心架構及不失實時性的前提下,借用系統的兩個優先順序任務,充當時鐘源和同級任務輪詢引擎,將µC/OS-II擴展出192個同級任務,且同級任務在最低優先順序任務下輪流執行。實驗表明,文中方法是可行的。文中的工作僅對核心中任務排程模組進行了擴充套件,要做一個完善可靠、支援同級任務排程的µC/OS-II系統,還需要對核心其它模組進行修改(如訊號量、郵箱、排程演算法優化等),這將是下一步要進行的工作。

參考文獻

[1] LABROSSE J.嵌入式實時作業系統µC/OS-II[M].(第2版)邵貝貝,譯.北京:北京航空航天大學出版社,2003:72-142 , 283-366.

[2]成後發,楊春金.µC/OS-II 作業系統核心的改進[J].通訊和計算機, 2006, 19 (6):52-55.

[3]鄒航,李小文.µC/OS-II 核心任務排程演算法的改進[J].重慶郵電大學學報:自然科學版,2010, 22 (3):360 – 363.

[4]何海濤.µC/OS-II中優先順序搶佔的時間片排程演算法的實現[J].計算機系統應用.2009,(11):73 -75

[5]任哲.嵌入式實時作業系統µC/OS-II原理及應用[M].北京:北京航空航天大學出版社,2005:15-97.

[6]姚燕南,薛鈞義,姚向華等.微型計算機原理與介面技術[M].北京:高等教育出版社,2004:115-122.

[7] µC/OS-II 2.52 [CP].http://www.micrium.com.