俞佳敏,王成群,徐偉強
(浙江理工大學 信息學院,浙江 杭州310018)
μC/OS-II作為一個開源的嵌入式實時操作系統,包含任務管理與任務調度,具有小巧、實時性強、移植性好[1-4]、基于優先級的多任務可剝奪等優點[5]。在μC/OS-II系統運行過程中,任務管理函數通過中斷操作,確保當前處于就緒狀態的最高優先級任務最先運行,能夠保證任務的實時性。近年來,μC/OS-II已在控制器[6]、數據采集[7]以及物聯網[8]等諸多領域取得了諸多應用。
除實際應用之外,近年來也出現了諸多對μC/OS-II性能分析及提升的成果。Lv[9]等采用靜態方法分析了μC/OS-II作為實時操作系統的最壞執行時間;朱怡安[10]等基于μC/OS-II提出了一種高可靠性的分區嵌入式操作系統內核,并通過實驗進行了驗證;隋宇暉[11]等提出了基于FPGA的硬件加速模塊,將μC/OS-II中的調度器與定時器進行硬件化,有效地提高了系統的實時性;李巖[12]等提出基于μC/OS-II的混合調度算法對同級任務進行分組調度,并在FPGA中實現了該算法,有效降低了系統的開銷并提高了關鍵任務的實時性;許璐璐[13]等提出采用增量鏈表的方式對任務延時進行高效管理。然而這些成果都是基于μC/OS-II最大64個優先級任務,隨著μC/OS-II在工業等行業運用得越來越廣泛,64個優先級任務已無法滿足目前的需求。因此,本文研究了μC/OS-II的優先級擴展,實現了最大512個優先級任務。
μC/OS-II給每一個任務分配一個惟一優先級,各優先級用一個正整數表示,優先級大小與該整數值成正比,即0為最大優先級,數值越大,優先級越小。μC/OS-II系統將在當前已處于就緒狀態的任務中選擇最高優先級的任務進行調度[14]。μC/OS-II最大支持64個任務優先級,即優先級范圍為(0~63),其中統計任務以及空閑任務等系統任務占用最低的兩個優先級,導致實際可用的任務優先級數減少。
μC/OS-II中定義了一個用于存放任務準備就緒標志的就緒表,就緒表為每次任務切換提供可確定性的時間保證。為了就緒表的正常使用,uCOS-II定義了變量OSRdyGrp和OSRdyTbl[7],以及表格優先級判斷表OSUnMapTbl[256][15]。如圖1所示,由于μC/OS-II最大支持64個優先級,就緒表由一個8乘8的表格組成,每個格子內為0或1,其中置1則代表該優先級下的任務處于就緒狀態。實質上,就緒表被分成8行,即每一行分別為8個優先級,其中OSRdyGrp為8位正整數類型,若第n(0≤n≤7)行中有相應優先級的任務就緒,則該位置1,否則默認為0。

圖1 μC/OS-II就緒表
數組OSRdyTbl[7]中每一個數均為8位正整數類型,OSRdyTbl[n](0≤n≤7)中的8位分別代表第n行中8個優先級任務就緒情況,若相對應位置的任務就緒,則置1,否則默認為0。μC/OS-II中優先級prio定義為一個8位正整數類型的變量,最大64個優先級時僅用到前6位,通過規律可以發現,低3位X可以代表該優先級在就緒表某行中位置,3位Y可以確定該優先級具體所在的行數。圖2為μC/OS-II提供的優先級判斷表OSUnMapTbl[256],優先級判斷表由位掩碼表轉換而來。通過該表以及OSRdyGrp和OSRdyTbl[7]這兩個變量,任務調度時能夠快速找到目前處于就緒狀態的優先級最高的任務。

圖2 μC/OS-II優先級判斷表
為了使μC/OS-II最大支持512個優先級任務,首先將變量prio擴展至16位正整數類型,并且采用16乘32的就緒表,即共16行,每行有32個優先級任務是否就緒的標志。相應地,OSRdyGrp擴展至16位正整數類型,OSRdyTbl[7]擴展至OSRdyTbl[15],且其中每個數擴展為32位正整數類型。但是在這種情況下,按照μC/OS-II所提供在優先級判斷表基礎上采用OSRdyGrp和OSRdyTbl[]計算目前就緒的最高優先級任務的算法不再適用。這是由于當前OSRdyTbl[]中個數為32位正整數類型,無法在16乘16的優先級判斷表中進行匹配查找。一種解決該問題的方法是將優先級判斷表擴展至16乘32的形式,但這樣無疑會大大浪費寶貴的空間資源。為此,本文在擴展優先級過程中采用按位判斷的方式實現在原來的優先級判斷表中查找當前就緒的最高優先級任務。
具體地,對于16位的優先級變量,通過低5位可以確定該優先級任務在就緒表中某行中的具體位置X,通過第6~9位可以確定具體所在的行數Y。X,Y分別可以表示為:
Y= (prio >> 5) & 0xFF,
X= (prio & 0x1F);
為將計算得到X,Y更新至就緒表中,X,Y需轉換為BitX,BitY:
BitX= 1 < BitY= 1 < 隨后更新變量OSRdyGrp和OSRdyTbl[]: OSRdyGrp |= BitY, OSRdyTbl[OSTCBY] |=BitX。 通過上述步驟,已經能夠成功將0~511之間的優先級變量分解并更新至就緒表中。此外,要實現擴展優先級的另一個重要難點在于如何通過OSRdyGrp和OSRdyTbl[]在μC/OS-II原有的優先級判斷表中尋找當前就緒的最高優先級任務。對此,采用分類討論的方法去尋找就緒的最高優先級任務。 首先,通過OSRdyGrp確定目前就緒的最高優先級任務所在行y,由于優先級判斷表輸入值在0x00~0xFF之間,所以分為以下2種情況計算y值: if ((OSRdyGrp & 0xFF) != 0) { y= OSUnMapTbl[OSRdyGrp & 0xFF];} else { y= OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8; }。 然后需要計算的是第y行中最高優先級所在的位置x。在優先級任務擴展為512時,就緒表每行為32個不同優先級,即x取值范圍為0~31,而μC/OS-II原有的優先級判斷表輸出的x最大值為7,顯然無法滿足此時的需求。因此采用逐級查找的方式確定x值,即首先判斷OSRdyTbl[y]的低8位是否為0x00,若為0,則在該行的第0~7個位置對應已就緒的優先級任務不存在;若不為0x00,則代表在第0~7個位置上有對應已就緒的優先級任務,則直接用OSRdyTbl[y]的低8位放入優先級判斷表中得到x。當OSRdyTbl[y]的低8位為0時,檢查OSRdyTbl[y]的第9~16位是否為0x00,若是,則表示在該行的第8~15個位置對應已就緒的優先級任務不存在;反之則代表在第8~15個位置上有對應已就緒的優先級任務,則直接用OSRdyTbl[y]的低8位放入優先級判斷表中,將判斷表輸出的值加8即為所求x的值,加上數值8是由于優先級判斷表只輸出該x在第8~15個位置中的相對位置,所以需要再加上未包含進去的數值8。同樣地,依次類推,當OSRdyTbl[y]的第1~16位為0x0000時,依次計算第17~24位以及第25~32位的情況,若滿足條件,則分別加上數值16或24以得到x。具體關鍵實現代碼如下: ptbl = &OSRdyTbl[y]; if ((*ptbl & 0xFF) != 0) { x= OSUnMapTbl[(*ptbl & 0xFF)];} else{ if (((*ptbl >> 8) & 0xFF) != 0) { x= OSUnMapTbl[((*ptbl >> 8) & 0xFF)] + 8;} else { if (((*ptbl >> 16) & 0xFF) != 0){ x= OSUnMapTbl[((*ptbl >> 16) & 0xFF] +16;} else{ if (((*ptbl >> 24) & 0xFF) != 0){ x= OSUnMapTbl[((*ptbl >> 24) &0xFF)]+ 24;} } } } } 計算得到x,y便可以計算當前就緒的最高優先級任務的優先級數值OSPrioHighRdy,具體如下: OSPrioHighRdy = (y<< 5) +x; 至此,通過上述分類考慮的方法,成功實現了通過OSRdyGrp和OSRdyTbl[]在μC/OS-II原有的優先級判斷表中找到當前就緒的最高優先級任務。同時實現了將μC/OS-II支持的最大優先級任務個數從64個提高到512個。 在實驗驗證中,分別創建優先級為2,14,48,128,255,300,356,454,508的任務,并且上述任務創建后即進入就緒狀態。由于兩個系統任務統計任務以及空閑任務分別占用了最低的510與511兩個優先級,為了體現這一點,設置上述創建的任務分別執行一次就停止,并只運行一次統計任務,這樣系統才會開始運行空閑任務。實驗結果如圖3所示,所有任務被成功創建,且按照優先級順序從高往低運行,當系統無就緒的用戶任務時,空閑任務將一直運行。圖3中y與x值分別體現了該任務在就緒表中的位置。同時,統計任務以及空閑任務占據最低的兩個優先級,符合實驗的預期結果。 圖3 實驗結果 通過實驗結果,驗證了本文提出的優先級擴展方法成功地將μC/OS-II支持的最大優先級任務個數提高到了512。 通過研究μC/OS-II的優先級設置機制,在原優先級判斷表的基礎上,采用分類判斷的方式將其支持的最大優先級數擴展到512個。通過實驗驗證,該方法成功地實現了最大優先級數的擴展,并未增加系統的空間。擴展μC/OS-II支持的最大優先級數能夠使其被應用得更加廣泛,進一步促進μC/OS-II的發展。3 實驗驗證及分析

4 結束語