,,,
(1.西安工業大學 計算機科學與工程學院,西安 710021; 2.西北工業大學 計算機學院,西安 710072)
在實時操作系統中,事件觸發指一個任務只有在與之相關的特定事件發生的條件下才能開始運行。早在最初的嵌入式領域中,事件觸發機制已經得到了廣泛應用[1],然而在航空、航天及核電等領域,由于系統的高可靠性與硬實時性要求,事件觸發方式無論在設計,還是維護方面都存在較大困難[2]。許多任務可能因為等待資源而超時,這樣就無法滿足任務的實時性要求,更無法保證安全關鍵任務的完成。為此,很多基于事件觸發的操作系統變得愈發復雜,不僅降低了研發效率,而且增加了維護成本[3]。
時間觸發機制指在預先計劃好的時間點執行系統行為,從而使系統具有良好的先驗性和確定性[4]。時間觸發設計思想中時間可控的特點從根本上提高了系統的實時性,避免了可能的直接沖突。因此,對于任務確定的嵌入式系統,時間觸發設計思想具有明顯優勢[5-7]。然而單純采用時間觸發的系統在某種程度上會降低系統的靈活性和動態交互性,很難完全滿足多樣性的系統需求,尤其針對混合關鍵任務的執行[8-10]。因此,在實際應用中,往往需要將時間觸發和事件觸發機制相結合,設計出一種支持時間觸發和事件觸發的混合調度機制。
由于μC/OS-II是一款僅支持事件觸發的開源、可移植、可裁剪的的實時操作系統,通過分析該系統的特點,將其改造為支持兩種觸發機制的操作系統。
μC/OS-II操作系統中的任務由三個部分組成:任務程序代碼,任務堆棧和任務控制塊。
任務程序代碼通常被設計為一個無限循環結構。在這個循環中可以響應中斷。任務堆棧是給每個任務分配的一塊獨立的連續內存空間,用來在任務切換和響應中斷時保存CPU寄存器中的內容,或任務調用其他函數時使用。任務控制塊(Task Control Block, TCB)的數據結構OS_TCB,用來記錄任務的堆棧指針、任務的當前狀態、任務的優先級等一系列與任務管理有關的屬性。
任務調度主要包括兩部分內容:一是判斷哪些任務處于就緒狀態;二是從處于就緒態的任務中確定應該馬上執行的任務并為其分配CPU。μC/OS-II中完成第一部分工作的是任務就緒表,完成第二部分工作的是調度器。μC/OS-II中設計了一個位圖來登記系統中所有處于就緒狀態的任務,這個位圖就是任務就緒表。位圖的每一位代表系統中的每一個任務,該位置的狀態(1或0)就表示對應任務是否處于就緒狀態。
為了能夠同時支持TT(Time-Triggered)任務和ET (Event-Triggered) 任務,將系統分為兩大部分:時間觸發模塊和事件觸發模塊,這兩部分相對獨立又緊密聯系。以時間觸發模塊為上層主要模塊,事件觸發模塊為下層基礎模塊的層次性架構如圖1所示。

圖1 時間和事件雙重觸發的系統調度架構圖
應用API任務集輸入位于整個內核架構的最外層,包括對應用提供的系統服務、系統配置和用戶應用程序。系統配置模塊可以配置與具體應用相關的參數和選項等,用戶應用程序即包括用戶創建的任務,其中有時間觸發模塊提供的API,也有事件觸發模塊提供的API。
任務調度入口將應用API分為時間觸發任務和事件觸發任務。在調度器內核中,時間觸發模塊為TT任務的管理和調度服務,事件觸發模塊為ET任務進行管理和服務,該模塊仍然采用原μC/OS-II中的管理方法。
在TT任務調度中,系統任務僅由預設的時間點來觸發,調度器在運行期間每一時刻,都是通過提前計算好的調度表來進行調度決策的。
事件觸發模塊主要負責ET任務的管理、調度以及與安全性相關的訪問控制決策和實施。此外,還包括中斷管理和任務間通信等內核與硬件無關的部分。
包括與具體硬件平臺相關的任務堆棧管理、任務切換、時鐘中斷等模塊,根據不同的應用環境進行個性化移植。
整個內核中,時間觸發模塊占主體地位,系統為其預先分配固定的時間槽用以執行時間觸發任務,主要保證系統的可靠性和確定性。事件觸發模塊在時間觸發模塊的空閑時間內處理,而空閑時間也可以根據時間觸發任務的實際運行情況動態調整,提高了系統的靈活性。
時間觸發模塊主要完成TT任務的管理與調度、任務間的通信以及中斷管理等。為了更好的保留μC/OS-II的原有特性和代碼結構,時間觸發模塊的實現是在由改造μC/OS-II實現的事件觸發模塊之上,另外新建的一個模塊。其結構定義如下:
typedefstructos_tt_tcb
{OS_STK* OSTT_TCBStkPtr; /*TT任務的堆棧指針*/
ttTaskTypeOSTT_TCBTaskID; /*任務標識符*/
ttAppModeTypeOSTT_TCBAppMode; /*任務所屬應用模式*/
INT8U OSTT_TCBStartTime; /*TT任務的發布時間*/
INT8U OSTT_TCBDeadline; /*TT任務的時限時間*/
ttTaskStateTypeOSTT_TCBState; /*TT任務的狀態*/
INT8U criti_level; /*混合關鍵任務的關鍵級別*/
OS_TT_TASK_INFO info[MAX_CRITICALITY];
}OS_TT_TCB;
其中OS_TT_TASK_INFO包含時間觸發的關鍵任務處于各個關鍵級別時的信息,包括任務在各關鍵級別上的最壞執行時間和后續任務。而常量MAX_CRITICALITY表示系統的最大的關鍵級別數,如果MAX_CRITICALITY等于1,則表示系統中只有一種關鍵級別的任務,則整個任務的調度就簡化為普通的時間觸發任務調度,只需要一張調度表即可。OS_TT_TASK_INFO的定義如下:
typedefstructos_tt_task_info
{ INT8U OSTT_TCBWcet; /*TT任務的最壞執行時間*/
structos_tt_tcb* OSTT_TCBNext; /*指向下一個OS_TT_TCB的指針*/
}OS_TT_TASK_INFO;
和μC/OS-II一樣,事先定義了一批時間觸發任務控制塊,其數量由宏定義OS_TTTASK_MAX靜態配置。系統將建立一個空閑TT任務鏈表和一個TT任務控制塊鏈表來管理這些時間觸發任務控制塊。
時間觸發的任務調度需要多張調度表,每張調度表就是一個任務控制塊鏈表,對應每一個任務的優先級別。為此,設計了以下結構:
typedefstructos_tt_appmode
{
structos_tt_tcb* first[MAX_CRITICALITY]; /*指向任務的頭結點*/
}OS_TT_APPMODE;
structos_tt_tcb*類型的數組first包含了指向各張調度表中第一個TT任務控制塊的指針,即各個TT任務控制塊鏈表的頭結點指針。
為了更方便快捷地管理被搶占的TT任務,設計了任務恢復鏈表,將被搶占的TT任務的任務控制塊鏈接在一起,其中的任務按照最早時限排列,在恢復任務執行時,總是最先取出表頭時限時間最找的任務。TT任務恢復鏈表由任務恢復鏈表節點OS_TT_PREEMPTED_TCB鏈接而成,其定義如下:
typedefstructos_preempted_tt_tcb
{
OS_TT_TCB*OSTT_PTcb; /*指向需要恢復執行的時間觸發任務*/
structos_preempted_tt_tcb*OSTT_PNext; /*指向鏈表中下一個元素*/
}OS_TT_PREEMPTED_TCB;
和空閑TT任務鏈表類似,設計了一個OS_TT_PREEMPTED_TCB類型的數組OSTTPTCBTbl[],其元素個數由OS_TT_PREEMPTED_MAX靜態配置,表示系統最多可以維護被搶占的任務控制塊的個數。把各個元素鏈接成一個鏈表,這就是空閑TT任務恢復鏈表,其頭指針為OSTTPTCBFreeList,用于任務恢復鏈表節點的分配;OSTTResumeFirst和OSTTResumeLast分別為任務恢復鏈表頭與表尾指針。

圖2 任務控制塊鏈表和任務恢復鏈表
圖2表示了TT任務控制塊鏈表和空閑TT任務鏈表,任務恢復鏈表和空閑任務恢復鏈表及其相互間的關系。其中,OSTTCur表示當前正在運行的TT任務的控制塊,OSTTNext指向下一個將要運行的TT任務的控制塊。
時間觸發模塊中的任務調度和事件觸發一樣,也分為中斷級調度和任務級調度。
3.3.1 中斷級調度
時間觸發模塊中,中斷級調度主要發生在時鐘中斷服務程序OSTickISR()中,調度通過ttSchedTick()函數實現。中斷服務程序完成后退出中斷時,調用ttSchedTick()函數,該函數會確認是否開始新一輪調度、是否有新的TT任務需要運行、是否TT任務都已執行完等各種情況。
1)如果開始新一輪調度,則時鐘節拍重置為0,將當前執行任務指針OSTTCur置為NULL,將下一個將要執行的任務指針OSTTNext指向低級調度表中的第一個任務,開始重新執行;
如果不開始新一輪調度:
2)還沒到下一個TT任務的觸發時間,當前的TT任務還未執行完且執行時間未達到當前級別下的最壞執行時間時,則當前任務繼續執行,不進行任務切換;
3)當前的TT任務是高級別安全關鍵任務,執行時間已達到當前級別下的最壞執行時間而還未執行完時,則系統發生狀態切換,提高系統所處關鍵級別和調度表,根據調度表將OSTTNext指向高級調度表中下一任務,當前任務繼續執行,不進行任務切換;
4)如果下一個TT任務觸發,則搶占當前的TT任務并進行任務切換;
5)如果當前TT任務已執行完且下一個任務還未到達,則對時間觸發模塊來說,當前處于空閑時間,將系統切換到事件觸發模塊,進行ET任務的調度和切換。
中斷級調度中的任務切換不需要保存任務上下文,因為任務被中斷時已經進行了保存。中斷級調度的主要流程圖如圖3所示。

圖3 中斷級調度流程圖
3.3.2 任務級調度
時間觸發模塊中,任務級調度發生在任務執行完畢時,調用ttTaskEnd(),可以讓系統提前進行任務調度,而不必等時鐘中斷到來。
1)如果恢復鏈表為空,說明當前所有TT任務均已執行完畢,則將系統切換到事件觸發模塊,進行ET任務的調度和切換。
2)若恢復鏈表不為空,當前結束任務為恢復鏈表中最后一個任務,則將當前任務從恢復鏈表中刪除,啟動ET任務調度和切換。
3)若恢復鏈表不為空,當前結束任務不是恢復鏈表中最后一個任務,將當前任務從恢復鏈表中刪除,然后恢復鏈表中下一個TT任務的執行,進行TT任務的任務切換。
4)若恢復鏈表不為空,且當前任務不在恢復鏈表中,則將恢復鏈表中的第一個任務恢復運行,進行TT任務切換。
任務級調度的主要流程圖如圖4所示。

圖4 任務級調度流程圖
將設計的內核移植到Xilinx Virtex-5 FXT FPGA ML507 的評估平臺上進行測試。內核在開發板上的移植工作主要通過Xilinx ISE Design Suite 12.3軟件完成。實驗選取4個事件觸發任務(ET任務)和3個時間觸發任務(TT任務);任務的各項參數如表1和2所示。

表1 事件觸發任務

表2 時間觸發任務
ET任務的優先級數字越小表示其優先級越高,實驗環境下系統時鐘節拍為1 ms,TT任務執行周期為50 ms。在完成多次實驗后,選取任務開始執行的第一個周期內的執行結果,實驗結果如圖5所示。

圖5 實驗結果圖
由實驗結果可知,tick = 0時刻,ET任務etTask1,etTask2,etTask3,etIdle在任務創建完成后就緒,由于優先級etTask3 > etTask2 > etTask1 >etIdle,所以任務etTask3優先執行,此后etTask2,etTask1和etIdle依次執行。當tick = 10時,ttTask1開始執行,直到tick = 12時,ttTask1還未執行結束,這時ttTask2觸發并搶占ttTask1任務執行。當tick = 15時,ttTask2執行結束,ttTask1恢復執行;當tick = 22時,ttTask1執行結束。之后,ET任務etIdle,etTask2,etTask3依次就緒并執行。當tick = 30時,ttTask3搶占etTask3開始執行;在tick = 32時ttTask3執行結束,之后etTask3恢復執行并在tick = 37時執行結束。此后,ET任務etIdle,etTask1,etTask2依次就緒并執行。
隨著外部事件的不可預知性和實時任務復雜性的增加,單純的事件觸發機制或時間觸發機制都難以保證系統的安全性和可靠性。只有將事件觸發和時間觸發結合起來,才能解決單一觸發機制無法滿足復雜嵌入式系統要求的問題,才能既保證系統的可靠性和確定性,又保證系統對外部事件擁有良好的響應能力。實驗說明了這種方式可行,后期的工作將在時間觸發模塊內部,還要實現針對混合關鍵任務的調度算法和對應的安全級別調度表的設計,保證系統對安全關鍵任務的支持。在事件觸發模塊內部,還要實現包括決策和實施在內的訪問控制機制,保證系統具備一定的安全性。