摘要:NUT/OS是一個實時的嵌入式操作系統,源碼完全公開且免費。該文通過研究其內核可以更好的理解嵌入式操作系統的實現原理,重點分析了NUT/OS系統中的任務調度機制,時間管理機制,任務管理機制以及內存管理機制的實現原理,并指出NUT/OS在移植過程中面臨的困難。
關鍵詞:實時操作系統;NUT/OS;任務調度;內存管理
中圖分類號:TP316文獻標識碼:A 文章編號:1009-3044(2009)36-10371-03
Principle and Implementation of NUT/OS
YANG Xiao-ping
(Faculty of Computer, Guangdong University of Technology, Guangzhou 510006, China)
Abstract: As a free and open-source embeded operate system,and because of its outstanding networking,NUT/OS is concerned greatly.this paper analyzes the architeture as well as principle and mechanism of NUT/OS’s kernel,and points out its disadvantage in the transparent.
Key words: RTOS; NUT/OS; task schedule; memory management
嵌入式實時操作系統(Real-Time Operating System)在目前的嵌入式應用中越來越顯示出其重要意義。采用嵌入式實時操作系統可以更合理、更有效地利用CPU的資源,簡化應用軟件的設計,縮短系統開發時間,更好地保證系統的實時性和可靠性。因而研究嵌入式操作系統內核的原理及其實現,使我們在實際的開發中選擇和應用操作系統時更加主動,更加靈活。
目前一些比較有名的免費的、源碼開放的操作系統有μClinux、μC/OS-Ⅱ和FreeRTOS等。NUT/OS作為一個網絡功能突出的嵌入式操作系統,在當今眾多嵌入式設備都需要接入網絡的情況下,其應用前景廣闊。NUT/OS是Ethernut項目組針對Ethernut開發板設計、開發的一套實時、多任務的嵌入式操作系統,其源代碼是完全公開免費的。
1 NUT/OS層次結構
針對8位MCU特點,NUT/OS很緊湊的實現了操作系統功能,核心具有任務調度管理,文件管理,內存管理,事件管理功能,外圍功能支持FAT、ROMEFS文件系統,網絡通訊以及設備管理。圖1是NUT/OS操作系統功能示意圖。
NUT/OS內核支持優先級調度算法,CPU總是讓處于就緒態的,優先級最高的任務最先運行。NUT/OS內核同時支持輪換調度算法,系統允許不同的任務可以使用相同的優先級,在沒有最高優先級任務就緒的情況下,相同優先級的任務共享CPU時間。
2 NUT/OS操作系統的原理和實現
2.1 任務調度管理
嵌入式實時操作系統的一個重要概念就是任務調度。在搶占式內核中,優先級高的任務一旦就緒就能搶占優先級低的任務的CPU使用權,這樣就提高了系統的實時響應能力。NUT/OS中沒有對任務的數量加以限制,任務優先級數的范圍相對μC/OS-Ⅱ來說也很大,優先級可以從0到254;同時NUT/OS支持優先權調度算法和輪轉調度算法,因此NUT/OS采用鏈表的方法進行任務的調度。系統定義了下面的鏈表和參數:
NUTTHREADINFO * nutThreadList; //全部線程列表
NUTTHREADINFO * runQueue;//全部就緒態按優先級排隊的線程列表
NUTTHREADINFO * runningThread;//當前正在運行的線程
NUT/OS總是運行就緒任務中優先級最高的那一個,系統運行中,當有優先級更高的任務插入到優先級就緒任務隊列時,系統就調用NutThreadSwitch()進行任務切換。調度只會在如下情況下發生:
1)運行中的進程受阻或自動放棄CPU;
2)運行中的進程“自殺”或“被殺”;
3)運行中的進程喚醒某個線程;
4)中斷服務子程序結束時喚醒其它進程;
5)新線程創建時。
2.2 任務管理的實現
任務管理包括如何在用戶的應用程序中建立任務、刪除任務、設定任務優先級、掛起和恢復任務,以及獲得任務的相關信息等。NUT/OS中每個任務對應一個任務控制塊,系統通過任務控制塊來感知和管理一個任務。任務控制塊的結構定義如下:
struct _NUTTHREADINFO {
NUTTHREADINFO *td_next;
//指向全部線程列表中的下一個
NUTTHREADINFO *td_qnxt;
//全部就緒態按優先級排隊的線程列表
volatile unsigned int td_qpec; //阻塞事件計數器
char td_name[9]; //線程的名字
uint8_t td_state;//線程的狀態
uintptr_t td_sp; //線程的堆棧指針
uint8_t td_priority;//線程的優先級
uint8_t *td_memory;
//指向堆棧中已使用的堆棧內存
HANDLE td_timer;//事件定時器
volatile HANDLE td_queue;
//等待隊列的根入口地址
};
可以通過調用下面的這個函數來創建一個線程:
HANDLE NutThreadCreate(char *name, void (*fn) (void *), void *arg, size_t stackSize);
創建線程的過程實際上就是從堆棧空間申請一個放置線程控制塊的空間,若申請成功,則建立線程控制塊并完成線程控制塊的初始化。接著將新創建的任務插入到就緒任務隊列,若當前任務的優先級最高且任務調度程序已經運行,則進行上下文切換。NutThreadCreate()成功返回時,將返回一個句柄,指向新任務控制塊的數據結構。
NUT/OS中的任務有4種狀態,分別是:睡眠態,等待態,就緒態和運行態。任務在系統中一定處于這4種狀態中的一種。在系統內核管理下,各個任務可以按照圖2所示進行狀態轉換。在內核NUT/OS中,為了任務調度的需要,處于運行態的任務的任務控制塊并不從就緒任務隊列中刪除,仍位于就緒隊列的首部。一旦發生中斷,運行態任務就進入就緒態。任務因等待某種資源、信號或者消息而無法繼續運行時就轉入等待態。出入等待態的任務獲得需要的資源后,重新進入就緒態。睡眠態是指任務駐留在程序空間沒有交由內核來管理。
當任務運行完之后,可以自行刪除。與μC/OS-Ⅱ不同的是,NUT/OS刪除任務時,先調用系統提供的函數NutThreadExit(),將該任務的優先級數設為255,任務從調度隊列中移出。此時任務的代碼和占用的空間并沒有被刪除, NUT/OS只是不在理會這個任務,該任務也不能再被調度執行。當空閑任務運行時,調用NutThreadDestroy(),將該任務占有的內存空間反還給系統。
2.3 時間管理的實現
時鐘管理也是系統內核的一個重要功能,它為用戶提供任務定時等系統服務。內核NUT/OS通過定時器數據結構NUTTIMERINFO和一個定時隊列NUTTIMERLIST來實現定時服務。定時隊列中,鏈接的基本結構為定時器數據結構。全局變量NUTTIMERLIST是定時隊列的頭指針。用戶定義并使用的定時器,在時間期限到來之前按定時的長短順序排放在定時隊列中,處在定時隊列后面定時器要等到其前面的定時器到期之后才能開始計時。
時鐘的節拍式中斷是任務實現超時或定時功能的依據.每發生一個時鐘節拍,函數NutTimer0Intr()首先將定時隊列上的第一個NUTTIMERINFO的時鐘節拍tn_ticks_left減1,并判斷該值是否為0.如果為0,說明該定時器的定時時間到期,則內核將該定時器的數據結構從定時隊列上刪除,同時將指向該定時器的任務從等待態轉為就緒態;接著繼續處理該隊列上位于隊首的下一個定時器數據結構NUTTIMERINFO,直到處理完該隊列上所有到期的任務。如果tn_ticks_left不為0,說明沒有定時器到期,則該函數不做任何處理直接結束。
NUT/OS提供的比較典型的時間管理函數NutDelay()和NutSleep(),它們都可以實現將一個任務延時一段時間的功能。但是使用NutSleep()只能將當前線程掛起整數個節拍的時間,時間只是時鐘節拍的整數倍,該函數不能實現精確延時。NutDelay()可以實現精確延時,它不會掛起當前線程,即當前線程仍然處于運行態。除非有更高優先級線程轉入就緒態,否則仍然擁有CPU的控制權。
2.4 內存管理的實現
每當任務、隊列、信號量創建時,都要向系統申請分配一定的內存空間。合理且靈活的內存管理不僅可以保證系統正確高效的運行,同時還可以提高系統可靠性。
NUT/OS采用堆的形式動態管理內存。堆中包含了系統的所有空閑內存塊,NUT/OS定義了一個全局指針heapFreeList指向堆入口,各個空閑塊按照地址排序。空閑塊的數據結構在系統中是這樣定義的:
typedef struct _HEAPNODE{
size_t hn_size;
//該空閑節點的大小
struct _HEAPNODE *hn_next;
//指向下一個空閑節點的指針
}HEAPNODE;
NUT/OS采用最佳擬合分配策略。當應用程序申請一個內存空間時,系統根據申請的大小搜索空閑鏈表,找到滿足要求的最小空閑塊。為了提高內存的使用效率,在空閑內存塊比請求的空間大并且兩者之差大于某個設定的閾值的情況下,系統將該空閑內存塊一分為二,一塊用于滿足用戶申請要求,另一塊作為新的空閑內存塊繼續留在空閑塊鏈表中。空間釋放時,查找空閑塊塊鏈表,按照地址先后順序插入到鏈表中,當待插入的節點與鏈表中的空閑節點在地址上是前后連續時,則合并成一個空閑節點。系統中用NutHeapAlloc()分配的空間,用戶需要顯式的調用NutHeapFree()釋放,否則會造成內存泄漏。
μC/OS-Ⅱ提供的內存管理機制是把連續的大塊的內存按照分區來管理,每個分區中包含整數個大小相同的塊。由于每個分區的大小相同,即使頻繁的申請和釋放內存塊也不會產生內存碎片,但是內存利用率不高。NUT/OS的內存管理策略,能夠使內存塊得到很好的使用。
3 NUT/OS的移植
μC/OS-Ⅱ自1992年以來,已經被移植到幾乎所有嵌入式應用類CPU上,許多行業都有成功應用該實時內核的實例。NUT/OS作為一個網絡功能突出的嵌入式操作系統,其應用前景廣闊。但是由于NUT/OS在開發時是針對特定的硬件環境進行的,包括網絡適配器的型號也是固定的,另外對硬件系統使用的時鐘也有特定的要求,因而在非Ethernut開發板上移植NUT/OS面臨著很多困難。移植過程中涉及到很多需要修改系統底層代碼的地方,其中最重要的是硬件啟動代碼的修改和審查,因為NUT/OS的網絡配置部分也在進入main()之前完成,這部分代碼如果需要硬件應答并由此阻塞則無法啟動操作系統。寫作本文的目的也是在于此,通過對系統內核的原理及其實現的分析,加深對其過程及各種機制的理解,為我們在實際的(不同于Ethernut開發板)硬件環境下移植和應用NUT/OS提供幫助。
4 結束語
隨著以太網的使用日益普遍,嵌入式設備也必將走入網絡化,為此需要一種簡單實用的網絡接入方案。運行于8位MCU上的NUT/OS實時系統提供了TCP/IP協議棧的支持,可以通過UART撥號方式或以太網接入網絡。NUT/OS的開發小組提供了操作系統源碼,并且處于對系統的不斷完善中。硬件版本和軟件版本也一直在更新,相信國內將有很多人來學習和使用這項新技術,NUT/OS操作系統的應用范圍也會越來越寬。
參考文獻:
[1] 許慶春,吳光敏.Nut/OS和μC/OS-II的實時調度算法比較[J].單片機及嵌入式系統應用,2006(5).
[2] 許慶春,吳光敏.Ethernut技術的研究與應用[D].昆明:昆明理工大學,2007.
[3] 閆麗,牛連強.Atmega128微控制器嵌入式內核的分析與改進[D].沈陽:沈陽工業大學,2005.
[4] Welcome to the Ethernut Project[EB/OL].http://www.ethernut.de.
[5] 楊云,張勇.基于ARM7的μC/OS-Ⅱ移植分析與實現[J].計算機工程與設計,2009(3):539-541.
[6] 楊科峰,邵時.嵌入式實時系統調度策略[J].計算機應用研究,2000(80):31.
[7] 何福貴,侯義斌,李輝.嵌入式操作系統調度機制的研究[J].計算機應用研究,2009(26).
[8] 高峰.嵌入式實時多任務微內核核心研究[D].成都:電子科技大學,2001.