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