|
[ 你可以任意轉(zhuǎn)載本文,但轉(zhuǎn)載請(qǐng)保留本段聲明。 作者將盡量追求內(nèi)容的正確,但不對(duì)正確性作出保證。 未經(jīng)作者許可,不得用于商業(yè)目的。 作者:byeyear/告別年代 Email: byeyear@hotmail.com ] RT-Thread是一個(gè)嵌入式實(shí)時(shí)操作系統(tǒng)核心,采用GPLv2授權(quán)。我從09年開始知道有RT-Thread這個(gè)東西,當(dāng)時(shí)其功能與uc/OS類似,如今三年多過去,RT-Thread已經(jīng)成長為哥斯拉了。其支持的arch和芯片大大增加,并且其外圍組件也相當(dāng)豐富,包括GUI、TCP/IP、FileSystem,支持模塊動(dòng)態(tài)加載,有興趣的可以訪問其網(wǎng)址: www. 寫在前面 在我閱讀一些代碼分析的文章時(shí),經(jīng)常發(fā)生的情況是,代碼能看明白,知道這段代碼是做什么的,但就是不明白為什么要這么做。本文希望能做到的一點(diǎn)是,不僅要分析代碼“做了什么”,還要分析“為什么要這么做”。 為什么要做代碼分析的工作 學(xué)習(xí),并在學(xué)習(xí)中更好的理解,從而能夠更好的使用。 RT-Thread官網(wǎng)已經(jīng)對(duì)RTT的內(nèi)核做了簡(jiǎn)要介紹,參見: http://www./dokuwiki/doku.php?id=rt-thread%E7%BC%96%E7%A8%8B%E6%8C%87%E5%8D%97 對(duì)于上述文檔已經(jīng)介紹過的內(nèi)容,本文將不再介紹。建議先看上述文檔,本文使用的一些名詞和術(shù)語直接引自上文。在上述文檔的基礎(chǔ)上,本文希望挖掘出一些更細(xì)節(jié)的東西。 分析過程盡量不涉及具體的硬件平臺(tái)。在必要時(shí),使用AT91SAM7X 這個(gè)BSP作為例子,KEIL對(duì)該CPU實(shí)現(xiàn)了完善的軟件仿真,可以一邊分析一邊在模擬器上跑。 我假定您熟悉使用RT-Thread進(jìn)行開發(fā)的基本過程,能夠使用RT-Thread完成一個(gè)簡(jiǎn)單的應(yīng)用。 開始 我們從內(nèi)核對(duì)象開始。 RT-Thread操作系統(tǒng)的所有內(nèi)核對(duì)象定義于rtdef.h。所有內(nèi)核對(duì)象有一個(gè)公共成員rt_object,定義如下:
為什么要給對(duì)象命名? name保存著對(duì)象的名字。盡管就操作系統(tǒng)自身的運(yùn)行而言,對(duì)象名稱并不是必須的,但為其命名可以使我們?cè)谡{(diào)試時(shí)區(qū)分各個(gè)對(duì)象。FinSH組件可以打印出對(duì)象名稱。
建議的命名規(guī)則 以下是我在使用RTT和其他一些RTOS(如uc/OS)的過程中自己使用的一套對(duì)象命名規(guī)則: 對(duì)象類型+對(duì)象名稱 對(duì)象類型使用兩個(gè)字符表示。例如,td表示thread,mx表示mutex。 假如我有一個(gè)Thread,函數(shù)名為PollUserInput,那么我給這個(gè)thread命名為tdPUI。這樣,一方面防止對(duì)象名重復(fù),另一方面,在使用FinSH調(diào)試時(shí),可以根據(jù)對(duì)象名知道該對(duì)象的用途。 flag有什么用? 例如,flag中有一位表示該對(duì)象是系統(tǒng)對(duì)象(靜態(tài)分配)還是動(dòng)態(tài)對(duì)象。當(dāng)一個(gè)對(duì)象不再使用時(shí),將根據(jù)這一位決定是否釋放對(duì)象所占據(jù)的內(nèi)存。 list 有了這個(gè)成員,各個(gè)相同類型的對(duì)象就可以形成鏈表,以便管理。 rt_object成員一般放置于各對(duì)象的開頭。例如:
這就保證了各對(duì)象的起始地址同樣就是嵌入在該對(duì)象頭部的rt_object的起始地址。這樣我們就可以方便的使用指針統(tǒng)一訪問各對(duì)象,而不管該對(duì)象是什么類型。 下面這條語句訪問某內(nèi)核對(duì)象內(nèi)嵌的rt_object對(duì)象中的list成員,而不管該對(duì)象是什么類型: ((struct rt_object *)(&some_kernel_obj))->list; 初步了解內(nèi)核對(duì)象后,我們來看一個(gè)操作系統(tǒng)最基礎(chǔ)的設(shè)施:線程和線程調(diào)度。 線程對(duì)象由struct rt_thread描述,定義于rtdef.h中。這里就不再將該結(jié)構(gòu)體列出,直接分析其成員。作用比較明顯的成員不再一一分析,僅分析比較關(guān)鍵的幾個(gè)成員。 開頭的4個(gè)成員(name, type, flags, list)實(shí)際上就是rt_object結(jié)構(gòu)的成員。絕大多數(shù)內(nèi)核對(duì)象(rt_sem)在其頭部嵌入一個(gè)公共的rt_object結(jié)構(gòu),唯有rt_thread將這四個(gè)成員復(fù)制過來,應(yīng)該是出于效率方面的考慮。 接下來的tlist成員也是一個(gè)鏈表項(xiàng),根據(jù)線程狀態(tài)的不同,將利用該表項(xiàng)將線程對(duì)象掛到不同的鏈表中去。例如,如果線程處于ready狀態(tài),就將 通過tlist將該線程掛到ready線程鏈表;如果線程處于suspend狀態(tài),就通過tlist將線程掛到suspend線程鏈表。 current_priority和init_priority init_priority就是你創(chuàng)建線程時(shí)為其指定的優(yōu)先級(jí)。一般情況下這兩個(gè)值相等。但RTT允許你動(dòng)態(tài)改變線程的優(yōu)先級(jí),如果你這么做了,那么這兩個(gè)值是不相等的。 number、high_mask和number_mask 這三個(gè)成員用于快速查找當(dāng)前最高優(yōu)先級(jí)的線程。后面我們分析線程調(diào)度時(shí)再回到這三個(gè)成員上來。 event_set和event_info 用于進(jìn)程間的IPC。在IPC相關(guān)代碼中再詳細(xì)分析其作用。 init_tick和remaining_tick RTT允許多個(gè)線程使用同一優(yōu)先級(jí),在同一優(yōu)先級(jí)下的線程使用時(shí)間片調(diào)度。init_tick就是分配給該線程的時(shí)間片。當(dāng)某個(gè)優(yōu)先級(jí)的線程剛被選中進(jìn)入運(yùn)行態(tài)時(shí),remaining_tick將被賦予init_tick的值,并隨著線程的執(zhí)行而遞減。當(dāng)remaining_tick遞減到0,表明該線程的時(shí)間片用完,同一優(yōu)先級(jí)的下一個(gè)就緒線程將被選中進(jìn)入運(yùn)行態(tài)。 thread_timer 如果你在線程內(nèi)調(diào)用sleep,或者在等待資源時(shí)指定了超時(shí),RTT將使用thread_timer計(jì)算超時(shí)時(shí)間。 |
|
|