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