国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
走向 Linux 2.6
 


即將發(fā)布的新的穩(wěn)定的內(nèi)核支持更多類型的處理器,并且可靠性和可擴(kuò)展性得到了提高,因而將推動(dòng) Linux 得到更廣泛的應(yīng)用。在這里我們將重點(diǎn)介紹一些不同程度的變化,并給出部分代碼樣例。

Linux 內(nèi)核的開發(fā)已經(jīng)經(jīng)歷了一個(gè)漫長(zhǎng)的過程,最初是 Linus Torvalds 于1991年發(fā)布的原始的0.1版本,這個(gè)版本中包括一個(gè)基本的調(diào)度器、IPC(進(jìn)程間通信)和內(nèi)存管理算法。而現(xiàn)在它已經(jīng)是一個(gè)以往操作系統(tǒng)的實(shí)用的替 代品,在市場(chǎng)上表現(xiàn)出了強(qiáng)大的競(jìng)爭(zhēng)力。越來越多的政府機(jī)構(gòu)和IT巨頭的注意力正在轉(zhuǎn)向 Linux。從最小的嵌入式設(shè)備到 S/390,從手表到大型企業(yè)服務(wù)器,Linux 現(xiàn)在幾乎可以用于所有的地方。

Linux 2.6 是 Linux 開發(fā)周期中的下一個(gè)主要版本,它包括了一些強(qiáng)有力的特性,這些特性旨在改進(jìn)高端企業(yè)服務(wù)器的性能和支持越來越多的嵌入式設(shè)備(要了解更詳細(xì)的關(guān)于 Linux 2.6 對(duì)大型的、小型的以及多處理器系統(tǒng)支持問題的分析,請(qǐng)參閱 參考資料一節(jié)中到 Joseph Pranevich 的“Linux 的精彩世界”的鏈接)。

本文為關(guān)注 Linux 的用戶分析了 Linux 2.6 的一些重要特性,并且討論了驅(qū)動(dòng)程序開發(fā)人員可能會(huì)感興趣的多方面的變化。

Linux 2.6亮點(diǎn)

無(wú)論是對(duì)于企業(yè)服務(wù)器還是對(duì)于嵌入式系統(tǒng),Linux 2.6 都是一個(gè)巨大的進(jìn)步。對(duì)高端的機(jī)器來說,新特性針對(duì)的是性能改進(jìn)、可擴(kuò)展性、吞吐率,以及對(duì) SMP 機(jī)器 NUMA 的支持。對(duì)于嵌入式領(lǐng)域,添加了新的體系結(jié)構(gòu)和處理器類型——包括對(duì)那些沒有硬件控制的內(nèi)存管理方案的 MMU-less 系統(tǒng)的支持。并且,和往常一樣,為了滿足桌面用戶群的需要,添加了一整套新的音頻和多媒體驅(qū)動(dòng)程序。

在本文中,我們分析了 Linux 2.6的一些最引人關(guān)注的特性,但是仍有很多值得關(guān)注的變化,包括增強(qiáng)的內(nèi)核核心轉(zhuǎn)儲(chǔ)、快速互斥支持、改進(jìn)的I/O子系統(tǒng),等等,在這里我們不能全部討論。在 側(cè)欄中總結(jié)了其中一些,其余的我們?cè)?參考資料一節(jié)中給出了鏈接。





回頁(yè)首


新的調(diào)度器

2.6版本的 Linux 內(nèi)核使用了由 Ingo Molnar 開發(fā)的新的調(diào)度器算法,稱為O(1)算法,它在高負(fù)載的情況下執(zhí)行得極其出色,并且當(dāng)有很多處理器時(shí)也可以很好地?cái)U(kuò)展。

在 2.4版本的調(diào)度器中,時(shí)間片重算算法要求在所有的進(jìn)程都用盡它們的時(shí)間片以后,它們的新時(shí)間片才會(huì)被重新計(jì)算。這樣的話在一個(gè)有很多處理器的系統(tǒng)中,當(dāng) 進(jìn)程用完它們的時(shí)間片以后得等待重算(以得到新的時(shí)間片),從而導(dǎo)致大部分的處理器處于空閑狀態(tài);這將影響SMP的效率。除此之外,當(dāng)空閑的處理器開始執(zhí) 行那些時(shí)間片尚未用盡的處于等待狀態(tài)的進(jìn)程(如果它們自己的處理器忙),會(huì)導(dǎo)致進(jìn)程開始在處理器之間“跳躍”。當(dāng)一個(gè)高優(yōu)先級(jí)進(jìn)程或者交互式進(jìn)程發(fā)生跳躍 時(shí),整個(gè)系統(tǒng)的性能就會(huì)受到影響。

新的調(diào)度器解決上述問題的方法是,基于每個(gè) CPU 來分布時(shí)間片,并且取消了全局同步和重算循環(huán)。調(diào)度器使用了兩個(gè)優(yōu)先級(jí)數(shù)組,即活動(dòng)數(shù)組和過期數(shù)組,可以通過指針來訪問它們?;顒?dòng)數(shù)組中包含了所有映射到 某個(gè)CPU而且時(shí)間片尚未用盡的任務(wù)。過期數(shù)組中包含了一個(gè)時(shí)間片已經(jīng)用盡的所有任務(wù)的有序列表。如果所有活動(dòng)任務(wù)的時(shí)間片都已用盡,那么指向這兩個(gè)數(shù)組 的指針互換,過期數(shù)組(包含了準(zhǔn)備運(yùn)行的任務(wù))成為活動(dòng)數(shù)組,而空的活動(dòng)數(shù)組成為包含過期任務(wù)的新數(shù)組。數(shù)組的索引存儲(chǔ)在一個(gè)64位的位圖中,找到最高優(yōu) 先級(jí)的任務(wù)是很容易的。

新的調(diào)度器現(xiàn)在不再有大的 runqueue_lock。它維持每個(gè)處理器的運(yùn)行隊(duì)列/鎖機(jī)制,以使得兩個(gè)不同處理器上的兩個(gè)進(jìn)程可以完全并行地休眠、喚醒和上下文切換。重算循環(huán)(為進(jìn)程重新計(jì)算時(shí)間片)和 goodness 循環(huán)已經(jīng)被取消,O(1)算法用于 wakeup() 和 schedulee()。

新調(diào)度器的主要好處包括:

  • SMP效率:如果有工作需要完成,那么所有處理器都會(huì)工作。
  • 等待進(jìn)程:沒有進(jìn)程需要長(zhǎng)時(shí)間地等待處理器;同時(shí),沒有進(jìn)程會(huì)無(wú)端地占用大量的CPU時(shí)間。
  • SMP進(jìn)程映射:進(jìn)程只映射到一個(gè)CPU而且不會(huì)在CPU之間跳躍。
  • 優(yōu)先級(jí):不重要的任務(wù)的優(yōu)先級(jí)低(反之亦然)。
  • 負(fù)載平衡:調(diào)度器會(huì)降低那些超出處理器負(fù)載能力的進(jìn)程的優(yōu)先級(jí)。
  • 交互性能:使用新的調(diào)度器,即便是在非常高負(fù)載的情況下,系統(tǒng)花費(fèi)很長(zhǎng)時(shí)間來響應(yīng)鼠標(biāo)點(diǎn)擊或者鍵盤輸入的情況將不會(huì)再發(fā)生。




回頁(yè)首


內(nèi)核搶占

內(nèi)核搶占補(bǔ)丁在2.5系列中就已經(jīng)被打上,接下來在2.6中也會(huì)打。這將顯著地降低用戶交互式應(yīng)用程序、多媒體應(yīng)用程序等類似應(yīng)用程序的延遲。這一特性對(duì)實(shí)時(shí)系統(tǒng)和嵌入式系統(tǒng)來說特別有用。

2.5的內(nèi)核搶占模塊的工作由 Robert Love 完成。在先前的內(nèi)核版本中(包括2.4內(nèi)核),不允許搶占以內(nèi)核模式運(yùn)行的任務(wù)(包括通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核模式的用戶任務(wù)),直到它們自己主動(dòng)釋放 CPU。

在內(nèi)核2.6中,內(nèi)核是可搶占的。一個(gè)內(nèi)核任務(wù)可以被搶占,為的是讓重要的用戶應(yīng)用程序可以繼續(xù)運(yùn)行。這樣做最主要的優(yōu)勢(shì)在于,可以極大地增強(qiáng)系統(tǒng)的用戶交互性,用戶將會(huì)覺得鼠標(biāo)點(diǎn)擊和擊鍵的事件得到了更快速的響應(yīng)。

當(dāng)然,不是所有的內(nèi)核代碼段都可以被搶占??梢枣i定內(nèi)核代碼的關(guān)鍵部分,不允許搶占。鎖定可以確保每個(gè) CPU 的數(shù)據(jù)結(jié)構(gòu)和狀態(tài)始終受到保護(hù)而不被搶占。

以下的代碼片斷顯示了每個(gè) CPU 的數(shù)據(jù)結(jié)構(gòu)問題(在SMP系統(tǒng)中):


清單 1. 存在內(nèi)核搶占問題的代碼
          int arr[NR_CPUS];                                arr[smp_processor_id()] = i;                                /* kernel preemption could happen here */                                j = arr[smp_processor_id()]   /* i and j are not equal as                                smp_processor_id() may not be the same */                                

在這種情形下,如果在特定點(diǎn)發(fā)生了內(nèi)核搶占,任務(wù)將會(huì)由于重新調(diào)度而被分配到其他處理器——smp_processor_id() 將返回一個(gè)不同的值。

這種情形應(yīng)該通過鎖定來進(jìn)行保護(hù)。

FPU 模式是另外一種CPU應(yīng)該被保護(hù)起來不被搶占的情形。當(dāng)內(nèi)核在執(zhí)行浮點(diǎn)指令時(shí),F(xiàn)PU 狀態(tài)不被保存。如果這時(shí)發(fā)生了搶占,由于重新調(diào)度,F(xiàn)PU 狀態(tài)就會(huì)與搶占前完全不同。所以 FPU 代碼必須始終被鎖定,以防止內(nèi)核搶占。

鎖定可以這樣來實(shí)現(xiàn),在關(guān)鍵部分禁止搶占,在之后再激活搶占。以下是在2.6內(nèi)核中禁止和激活搶占的定義:

  • preempt_enable() -- 搶占計(jì)數(shù)器減1
  • preempt_disable() -- 搶占計(jì)數(shù)器加1
  • get_cpu() -- 先后調(diào)用 preempt_disable() 和 smp_processor_id()
  • put_cpu() -- 重新激活 preemption()

使用這些定義,清單 1可以重寫成這樣:


清單 2. 使用防搶占鎖的代碼
        int cpu, arr[NR_CPUS];                                arr[get_cpu()] = i;  /* disable preemption */                                j = arr[smp_processor_id()];                                /* do some critical stuff here */                                put_cpu()    /* re-enable preemption */                                

注意 preempt_disable()/enable()調(diào)用是可以嵌套的。也就是說,preempt_disable() 可以被調(diào)用 n 次,只有當(dāng)?shù)?n 次 preempt_enable() 被調(diào)用后,搶占才被重新激活。

當(dāng)使用自旋鎖時(shí),搶占是被隱式地禁止的。例如,一個(gè) spin_lock_irqsave() 調(diào)用會(huì)隱式地通過調(diào)用 preempt_disable() 來防止搶占;spin_unlock_irqrestroe() 通過調(diào)用 preempt_enable() 來重新激活搶占。

改進(jìn)的線程模型以及對(duì) NPTL 的支持
在2.5內(nèi)核中已經(jīng)做了很多的改進(jìn)線程性能的工作。在2.6中改進(jìn)的線程模型仍然是由 Ingo Molnar 來完成的。它基于一個(gè)1:1的線程模型(一個(gè)內(nèi)核線程對(duì)應(yīng)一個(gè)用戶線程),包括內(nèi)核內(nèi)在的對(duì)新的 NPTL(Native Posix Threading Library)的支持,這個(gè)新的 NPTL 是由 Molnar 和 Ulrich Drepper 合作開發(fā)的。

2.6內(nèi)核中其他引人注目的變化
  • 文件系統(tǒng)
    對(duì) ext2/ext3 文件系統(tǒng)做了改進(jìn),包括對(duì)擴(kuò)展屬性和POSIX訪問控制列表的支持。NTFS的驅(qū)動(dòng)程序也已經(jīng)重寫,可以支持(reentrant safe)SMP,大于4KB的簇,等等。同時(shí)2.6也支持 IBM 的 JFS(journaling file system) 和 SGI 的 XFS。
  • 音頻
    對(duì)桌面用戶而言,一個(gè)更令人期待的特性是稱為 ALSA(Advanced Linux Sound Architecture) 的新的 Linux 音頻體系結(jié)構(gòu),它取代了缺陷很多的舊的 OSS (Open Sound System)。新的聲音體系結(jié)構(gòu)支持USB音頻和MIDI設(shè)備,全雙工重放,等等。在桌面上播放 MP3 和其他音頻文件再也不會(huì)像以前那樣了!
  • 總線
    SCSI/IDE子系統(tǒng)經(jīng)過大幅度的重寫,一些驅(qū)動(dòng)程序仍然處于測(cè)試階段或者收尾階段。
  • 電源管理
    支持 ACPI(高級(jí)電源配置管理界面,Advanced Configuration and Power Interface),用于調(diào)整 CPU(可以在不同的負(fù)載下使CPU工作于不同的時(shí)鐘頻率以節(jié)電)和軟件掛起(這一特性仍在測(cè)試中)。
  • 聯(lián)網(wǎng)和IPSec
    內(nèi)核中加入了對(duì) IPSec (IP安全)的支持,因此也支持 IP 有效負(fù)載壓縮等各種 RFC。刪除了原來內(nèi)核內(nèi)置的HTTP服務(wù)器 kttpd。IPSec 特性使用了內(nèi)核提供的新的加密 API。這個(gè)加密API中包含了各種流行的算法,比如 MD4,MD5 DES,等等。加入了對(duì)新的 NFSv4 (網(wǎng)絡(luò)文件系統(tǒng))客戶機(jī)/服務(wù)器的支持。
  • 用戶界面層
    2.6內(nèi)核重寫了幀緩沖/控制臺(tái)層。這將意味著需要更新各種用戶空間幀緩沖工具,如 fbset 和 fbdesl。人機(jī)界面層還加入了對(duì)近乎所有可接入設(shè)備的支持,從觸摸屏到盲人用的設(shè)備,到各種各樣的鼠標(biāo)。

線程操作可以提高速度;2.6內(nèi)核現(xiàn)在可以處理任意數(shù)目的線程,PID最大可以到20億(IA32上)。

另外一個(gè)變化是引入了 TLS(Thread Local Storage)系統(tǒng)調(diào)用,這個(gè)調(diào)用允許分配一個(gè)或多個(gè) GDT(Global Descriptor Table)條目,作為線程注冊(cè)表。每個(gè) CPU 有一個(gè) GDT,每個(gè)條目對(duì)應(yīng)一個(gè)線程。這樣就可以實(shí)現(xiàn)一個(gè)不受創(chuàng)建的線程數(shù)限制的1:1線程模型(因?yàn)槊恳粋€(gè)新的內(nèi)核線程都是為一個(gè)用戶線程而創(chuàng)建)。2.4內(nèi)核中每個(gè)處理器最多只能支持8,192個(gè)線程。

系統(tǒng)調(diào)用 clone 被擴(kuò)展,以優(yōu)化線程的創(chuàng)建。如果 CLONE_PARENT_SETID 標(biāo)志被設(shè)置,內(nèi)核會(huì)把線程ID存儲(chǔ)在一個(gè)給定的內(nèi)存位置,如果當(dāng)線程結(jié)束時(shí) CLONE_CLEARID 標(biāo)志被設(shè)置,內(nèi)核就會(huì)把那個(gè)內(nèi)存位置清空。這有助于用戶級(jí)的內(nèi)存管理去識(shí)別沒有使用的內(nèi)存塊。同樣,對(duì)線程注冊(cè)表的信號(hào)安全加載的支持也已經(jīng)融入到這個(gè)體系中。當(dāng) pthread_join 發(fā)生時(shí)由內(nèi)核根據(jù)線程ID來完成 Futex(fast user space mutex)。(要了解futex的更多信息,請(qǐng)參閱 參考資料).

POSIX信號(hào)處理在內(nèi)核空間中完成。一個(gè)信號(hào)會(huì)傳遞給進(jìn)程中一個(gè)可用的線程;銷毀信號(hào)會(huì)終止整個(gè)進(jìn)程。停止和繼續(xù)信號(hào)也會(huì)影響整個(gè)進(jìn)程,這樣就可以實(shí)現(xiàn)對(duì)多線程進(jìn)程的工作控制。

引入了退出系統(tǒng)調(diào)用的一個(gè)變種,叫做 exit_group(),這個(gè)系統(tǒng)調(diào)用終止整個(gè)進(jìn)程和它的線程。此外,退出處理通過引入O(1)算法得到了改進(jìn),從而可以在兩秒內(nèi)終止一個(gè)具有成千上萬(wàn)個(gè)線程的進(jìn)程(而在2.4內(nèi)核中完成同樣的事情需要15分鐘)。

修改了 proc 文件系統(tǒng),不再報(bào)告所有的線程而只是報(bào)告原始的線程。這樣就避免了 /proc 報(bào)告速度的下降。內(nèi)核保證原始的線程在所有其他線程終止之前不會(huì)終止。





回頁(yè)首


虛擬內(nèi)存的變化

從虛擬內(nèi)存的角度來看,新內(nèi)核融合了 Rik van Riel 的 r-map (反向映射,reverse mapping)技術(shù),將顯著改善虛擬內(nèi)存 在一定程度負(fù)載下的性能。

為了理解反向映射技術(shù),讓我們來首先簡(jiǎn)單了解 Linux 虛擬內(nèi)存系統(tǒng)的一些基本原理。

Linux 內(nèi)核工作于虛擬內(nèi)存模式:每一個(gè)虛擬頁(yè)對(duì)應(yīng)一個(gè)相應(yīng)的系統(tǒng)內(nèi)存的物理頁(yè)。虛擬頁(yè)和物理頁(yè)之間的地址轉(zhuǎn)換由硬件的頁(yè)表來完成。對(duì)于一個(gè)特定的虛擬頁(yè),根據(jù)一 條頁(yè)表記錄可以找到對(duì)應(yīng)的物理頁(yè),或者是頁(yè)無(wú)法找到的提示(說明存在一個(gè)頁(yè)錯(cuò)誤)。但是這種"虛擬到物理"的頁(yè)映射不是總是一一對(duì)應(yīng)的:多個(gè)虛擬頁(yè)(被不 同的進(jìn)程共享的頁(yè))有可能指向同一個(gè)物理頁(yè)。在這種情況下,每個(gè)共享進(jìn)程的頁(yè)記錄將有指向?qū)?yīng)物理頁(yè)的映射。如果有類似這樣的情況,當(dāng)內(nèi)核想要釋放特定的 物理頁(yè)時(shí),事情會(huì)變得復(fù)雜,因?yàn)樗仨毐闅v所有的進(jìn)程頁(yè)表記錄來查找指向這個(gè)物理頁(yè)的引用;它只能在引用數(shù)達(dá)到0時(shí)才能釋放這個(gè)物理頁(yè),因?yàn)樗鼪]有別的辦 法可以知道是不是還存在實(shí)際指向這個(gè)頁(yè)的引用。這樣當(dāng)負(fù)載較高時(shí)會(huì)讓虛擬內(nèi)存變得非常慢。

反向地址映射補(bǔ)丁通過在結(jié)構(gòu)頁(yè)引入一個(gè)叫做 pte_chain 的數(shù)據(jù)結(jié)構(gòu)(物理頁(yè)結(jié)構(gòu))來解決這一問題。pte_chain 是一個(gè)指向頁(yè)的 PTE 的簡(jiǎn)單鏈接列表,可以返回特定的被引用頁(yè)的 PTE 列表。頁(yè)釋放一下子變得非常簡(jiǎn)單了。 不過,在這種模式中存在一個(gè)指針開銷。系統(tǒng)中的每一個(gè)結(jié)構(gòu)頁(yè)都必須有一個(gè)額外的用于 pte_chain 的結(jié)構(gòu)。在一個(gè)256M內(nèi)存的系統(tǒng)中,有64K個(gè)物理頁(yè),這樣就需要有 64KB * (sizeof(struct pte_chain)) 的內(nèi)存被分配用于 pte_chain 的結(jié)構(gòu)――一個(gè)很可觀的數(shù)字。

有一些可以解決這個(gè)問題的技術(shù),包括從結(jié)構(gòu)頁(yè)中刪掉 wait_queue_head_t 域(用于對(duì)頁(yè)的獨(dú)占訪問)。因?yàn)檫@個(gè)等待隊(duì)列極少用到,所以在 rmap 補(bǔ)丁中實(shí)現(xiàn)了一個(gè)更小的隊(duì)列,通過哈希隊(duì)列來找到正確的等待隊(duì)列。

盡管如此,rmap 的性能――尤其是處于高負(fù)載的高端系統(tǒng)――相對(duì)于2.4內(nèi)核的虛擬內(nèi)存系統(tǒng)還是有了顯著的提高。





回頁(yè)首


Linux 2.6的驅(qū)動(dòng)程序移植

2.6內(nèi)核給驅(qū)動(dòng)程序開發(fā)人員帶來了一系列非常有意義的變化。本節(jié)重點(diǎn)介紹將驅(qū)動(dòng)程序從2.4內(nèi)核移植到2.6內(nèi)核的一些重要方面。

首先,相對(duì)于2.4來說,改進(jìn)了內(nèi)核編譯系統(tǒng),從而獲得更快的編譯速度。加入了改進(jìn)的圖形化工具:make xconfig(需要Qt庫(kù))和make gconfig(需要GTK庫(kù))。

以下是2.6編譯系統(tǒng)的一些亮點(diǎn):

  • 當(dāng)使用make時(shí)自動(dòng)創(chuàng)建 arch-zImage 和模塊
  • 使用 make -jN 可以進(jìn)行并行的 make
  • make 默認(rèn)的不是冗余方式(可以通過設(shè)置 KBUILD_VERBOSE=1 或者使用 make V=1來設(shè)置為冗余方式)
  • make subdir/ 將編譯 subdir/ 及其子目錄下的所有文件
  • make help 將提供 make 目標(biāo)支持
  • 在任何一個(gè)階段都不需要再運(yùn)行 make dep

內(nèi)核模塊加載器也在2.5中完全被重新實(shí)現(xiàn),這意味著模塊編譯機(jī)制相對(duì)于2.4有了很大不同。需要一組新的模塊工具來完成模塊的加載和缷載 (他們的下載鏈接可以在 參考資料中找到),原來的2.4所用的 makefile 在2.6下不能再用。

新的內(nèi)核模塊加載器是由 Rusty Russel 開發(fā)的。它使用內(nèi)核編譯機(jī)制,產(chǎn)生一個(gè) .ko(內(nèi)核目標(biāo)文件,kernel object)模塊目標(biāo)文件而不是一個(gè) .o 模塊目標(biāo)文件。內(nèi)核編譯系統(tǒng)首先編譯這些模塊,并將其連接成為 vermagic.o。這一過程在目標(biāo)模塊創(chuàng)建了一個(gè)特定部分,以記錄使用的編譯器版本號(hào),內(nèi)核版本號(hào),是否使用內(nèi)核搶占等信息。

現(xiàn)在讓我們來看一個(gè)例子,分析一下新的內(nèi)核編譯系統(tǒng)如何來編譯并加載一個(gè)簡(jiǎn)單的模塊。這個(gè)模塊是一個(gè)“hello world”模塊,代碼和2.4模塊代碼基本類似,只是 module_init 和 module_exit 要換成 init_module 和 cleanup_module (內(nèi)核2.4.10模塊已經(jīng)使用這種機(jī)制)。這個(gè)模塊命名為 hello.c,Makefile 文件如下:


清單 3. 驅(qū)動(dòng)程序 makefile 文件示例
           KERNEL_SRC = /usr/src/linux                                SUBDIR = $(KERNEL_SRC)/drivers/char/hello/                                all: modules                                obj-m := module.o                                hello-objs := hello.o                                EXTRA_FLAGS += -DDEBUG=1                                modules:                                $(MAKE) -C $(KERNEL_SRC) SUBDIR=$(SUBDIR) modules                                

makefile 文件使用內(nèi)核編譯機(jī)制來編譯模塊。編譯好的模塊將被命名為 module.ko,并通過編譯 hello.c 和連接 vermagic 而獲得。KERNEL_SRC 指定內(nèi)核源文件所在的目錄,SUBDIR 指定放置模塊的目錄。EXTRA_FLAGS 指定了需要給出的編譯期標(biāo)記。

一 旦新模塊(module.ko)被創(chuàng)建,它可以被新的模塊工具加載或缷載。2.4中的原有模塊工具不能用來加載或缷載2.6的內(nèi)核模塊。這個(gè)新的模塊加載 工具會(huì)盡量減少在一個(gè)設(shè)備仍在使用的情況下相應(yīng)的模塊卻被缷載的沖突發(fā)生,而是在確認(rèn)這些模塊已經(jīng)沒有任何設(shè)備在使用后再缷載它。產(chǎn)生這種沖突的原因之一 是模塊使用計(jì)數(shù)是由模塊代碼自己來控制的(通過MOD_DEC/INC_USE_COUNT)。

在2.6中, 模塊不再需要對(duì)引用計(jì)數(shù)進(jìn)行加或減,這些工作將在模塊代碼外部進(jìn)行。任何要引用模塊的代碼都必須調(diào)用 try_module_get(&module),只有在調(diào)用成功以后才能訪問那個(gè)模塊;如果被調(diào)用的模塊已經(jīng)被缷載,那么這次調(diào)用會(huì)失敗。相應(yīng) 的,可以通過使用 module_put() 來釋放對(duì)模塊的引用。

內(nèi)存管理的變化
在2.5的開發(fā)過程中,加入了內(nèi)存池,以滿足無(wú)間斷地進(jìn)行內(nèi)存分配。其思想是預(yù)分配一個(gè)內(nèi)存池,并保留到真正需要的時(shí)候。一個(gè)內(nèi)存池由 mempool_create() 調(diào)用來創(chuàng)建(應(yīng)該包含頭文件 linux/mempool.h)。

mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,                                
mempool_free_t *free_fn, void *pool_data);

在這里 min_nr 是需要預(yù)分配對(duì)象的數(shù)目,alloc_fn 和 free_fn 是指向內(nèi)存池機(jī)制提供的標(biāo)準(zhǔn)對(duì)象分配和回收例程的指針。他們的類型是:

typedef void *(mempool_alloc_t)(int gfp_mask, void *pool_data);                                
typedef void (mempool_free_t)(void *element, void *pool_data);

pool_data 是分配和回收函數(shù)用到的指針,gfp_mask 是分配標(biāo)記。只有當(dāng) __GFP_WAIT 標(biāo)記被指定時(shí),分配函數(shù)才會(huì)休眠。

在池中分配和回收對(duì)象是由以下程序完成的:

void *mempool_alloc(mempool_t *pool, int gfp_mask);                                
void mempool_free(void *element, mempool_t *pool);

mempool_alloc() 用來分配對(duì)象;如果內(nèi)存池分配器無(wú)法提供內(nèi)存,那么就可以用預(yù)分配的池。

系統(tǒng)使用 mempool_destroy() 來回收內(nèi)存池。

除了為內(nèi)存分配引入了內(nèi)存池之外,2.5內(nèi)核還引入了三個(gè)用于常規(guī)內(nèi)存分配的新的GFP標(biāo)記,它們是:

  • __GFP_REPEAT -- 告訴頁(yè)分配器盡力去分配內(nèi)存。如果內(nèi)存分配失敗過多,應(yīng)該減少這個(gè)標(biāo)記的使用。
  • __GFP_NOFAIL -- 不能出現(xiàn)內(nèi)存分配失敗。這樣,由于調(diào)用者被轉(zhuǎn)入休眠狀態(tài),可能需要一段比較長(zhǎng)的時(shí)間才能完成分配,調(diào)用者的需求才能得到滿足。
  • __GFP_NORETRY -- 保證分配失敗后不再重試,而向調(diào)用者報(bào)告失敗狀態(tài)。

除了內(nèi)存分配的變化以外,remap_page_range()調(diào)用——用來映射頁(yè)到用戶空間——也經(jīng)過了少量修改。相對(duì)于2.4來說,現(xiàn)在它多了一個(gè)參數(shù)。虛擬內(nèi)存區(qū)域(VMA)指針要作為第一個(gè)參數(shù),然后是四個(gè)常用的參數(shù)(start,end,size 和 protection 標(biāo)記)。





回頁(yè)首


工作隊(duì)列接口

工作隊(duì)列接口是在2.5的開發(fā)過程中引入的,用于取代任務(wù)隊(duì)列接口(用于調(diào)度內(nèi)核任務(wù))。每個(gè)工作隊(duì)列有一個(gè)專門的線程,所有來自運(yùn)行隊(duì)列的任務(wù)在進(jìn)程的 上下文中運(yùn)行(這樣它們可以休眠)。驅(qū)動(dòng)程序可以創(chuàng)建并使用它們自己的工作隊(duì)列,或者使用內(nèi)核的一個(gè)工作隊(duì)列。工作隊(duì)列用以下方式創(chuàng)建:

struct workqueue_struct *create_workqueue(const char *name);                                

在這里 name 是工作隊(duì)列的名字。

工作隊(duì)列任務(wù)可以在編譯時(shí)或者運(yùn)行時(shí)創(chuàng)建。任務(wù)需要封裝為一個(gè)叫做 work_struct 的結(jié)構(gòu)體。在編譯期初始化一個(gè)工作隊(duì)列任務(wù)時(shí)要用到:

DECLARE_WORK(name, void (*function)(void *), void *data);                                

在這里 name 是 work_struct 的名字,function 是當(dāng)任務(wù)被調(diào)度時(shí)調(diào)用的函數(shù),data 是指向那個(gè)函數(shù)的指針。

在運(yùn)行期初始化一個(gè)工作隊(duì)列時(shí)要用到:

INIT_WORK(struct work_struct *work, void (*function)(void *), void *data);                                

用下面的函數(shù)調(diào)用來把一個(gè)作業(yè)(一個(gè)類型為work_struct 結(jié)構(gòu)的工作隊(duì)列作業(yè)/任務(wù))加入到工作隊(duì)列中:

int queue_work(struct workqueue_struct *queue, struct work_struct *work);                                
int queue_delayed_work(struct workqueue_struct *queue, struct work_struct
*work, unsigned long delay);

在queue_delay_work()中指定 delay,是為了保證至少在經(jīng)過一段給定的最小延遲時(shí)間以后,工作隊(duì)列中的任務(wù)才可以真正執(zhí)行。

工作隊(duì)列中的任務(wù)由相關(guān)的工作線程執(zhí)行,可能是在一個(gè)無(wú)法預(yù)期的時(shí)間(取決于負(fù)載,中斷等等),或者是在一段延遲以后。任何一個(gè)在工作隊(duì)列中等待了無(wú)限長(zhǎng)的時(shí)間也沒有運(yùn)行的任務(wù)可以用下面的方法取消:

int cancel_delayed_work(struct work_struct *work);                                

如果當(dāng)一個(gè)取消操作的調(diào)用返回時(shí),任務(wù)正在執(zhí)行中,那么這個(gè)任務(wù)將繼續(xù)執(zhí)行下去,但不會(huì)再加入到隊(duì)列中。清空工作隊(duì)列中的所有任務(wù)使用:

void flush_workqueue(struct workqueue_struct *queue);                                

銷毀工作隊(duì)列使用:

     void destroy_workqueue(struct workqueue_struct *queue);                                

不是所有的驅(qū)動(dòng)程序都必須有自己的工作隊(duì)列。驅(qū)動(dòng)程序可以使用內(nèi)核提供的缺省工作隊(duì)列。由于這個(gè)工作隊(duì)列由很多驅(qū)動(dòng)程序共享,任務(wù)可能會(huì)需要比較長(zhǎng)一段時(shí)間才能開始執(zhí)行。為了解決這一問題,工作函數(shù)中的延遲應(yīng)該保持最小或者干脆不要。

需要特別注意的是缺省隊(duì)列對(duì)所有驅(qū)動(dòng)程序來說都是可用的,但是只有經(jīng)過GP許可的驅(qū)動(dòng)程序可以用自定義的工作隊(duì)列:

  • int schedule_work(struct work_struct *work); -- 向工作隊(duì)列中添加一個(gè)任務(wù)
  • int schedule_delayed_work(struct work_struct *work, unsigned long delay); -- 向工作隊(duì)列中添加一個(gè)任務(wù)并延遲執(zhí)行

當(dāng)模塊被缷載時(shí)應(yīng)該去調(diào)用一個(gè) flash_scheduled_work() 函數(shù),這個(gè)函數(shù)會(huì)使等待隊(duì)列中所有的任務(wù)都被執(zhí)行。

中斷例程的變化
2.5的中斷處理程序內(nèi)部已經(jīng)經(jīng)歷了許多變化,但是絕大部分對(duì)于普通的驅(qū)動(dòng)程序開發(fā)者來說沒有影響。不過,還是有一些重要的變化會(huì)影響到驅(qū)動(dòng)程序開發(fā)者。

現(xiàn)在的中斷處理函數(shù)的返回代碼是一個(gè) irqreturn_t 類型。這個(gè)由 Linus 引入的變化意味著中斷處理程序告訴通用的 IRQ 層是否真的要中斷。這樣做是為了當(dāng)中斷請(qǐng)求不斷到來時(shí)(原因是驅(qū)動(dòng)程序偶然激活了一個(gè)中斷位或者硬件壞掉了),捕獲假中斷(尤其是在共享的PCI線上), 而任何驅(qū)動(dòng)程序?qū)Υ硕际菬o(wú)能為力的。在2.6中,驅(qū)動(dòng)程序如果要從一個(gè)設(shè)備上發(fā)出一個(gè)中斷需要返回 IRQ_HANDLED,如果不是的話返回 IRQ_NONE。這樣可以幫助內(nèi)核的 IRQ 層清楚地識(shí)別出哪個(gè)驅(qū)動(dòng)程序正在處理那個(gè)特定的中斷。如果一個(gè)中斷請(qǐng)求不斷到來而且沒有注冊(cè)那個(gè)設(shè)備的處理程序(例如,所有的驅(qū)動(dòng)程序都返回 IRQ_NONE),內(nèi)核就會(huì)忽略來自那個(gè)設(shè)備的中斷。缺省情況下,驅(qū)動(dòng)程序 IRQ 例程應(yīng)該返回 IRQ_HANDLED,當(dāng)驅(qū)動(dòng)程序正在處理那個(gè)中斷時(shí)卻返回了 IRQ_NONE,說明存在 bug。新的中斷處理程序可能是類似于這樣:


清單 4. 2.6的中斷處理程序偽代碼
             irqreturn_t irq_handler(...) {                                ..                                if (!(my_interrupt)                                return IRQ_NONE;  // not our interrupt                                ...                                return IRQ_HANDLED;  // return by default                                }                                

注意,cli(),sti(),save_flags()和 restor_flags() 是不贊成使用的方法。取而代之的是 local_save_flags() 和 local_irq_disable(),用來禁止所有的本地中斷(本處理器內(nèi)的)。禁止所有處理器的中斷是不可能的。





回頁(yè)首


統(tǒng)一的設(shè)備模型

2.5開發(fā)過程中另一個(gè)最值得關(guān)注的變化是創(chuàng)建了一個(gè)統(tǒng)一的設(shè)備模型。這個(gè)設(shè)備模型通過維持大量的數(shù)據(jù)結(jié)構(gòu)囊括了幾乎所有的設(shè)備結(jié)構(gòu)和系統(tǒng)。這樣做的好處是,可以改進(jìn)設(shè)備的電源管理和簡(jiǎn)化設(shè)備相關(guān)的任務(wù)管理,包括對(duì)以下信息的追蹤:

  • 系統(tǒng)中存在的設(shè)備,其所連接的總線
  • 特定情形下設(shè)備的電源狀態(tài)
  • 系統(tǒng)清楚設(shè)備的驅(qū)動(dòng)程序,并清楚哪些設(shè)備受其控制
  • 系統(tǒng)的總線結(jié)構(gòu):哪個(gè)設(shè)備連接在哪個(gè)總線上,以及哪些總線互連(例如,USB和PCI總線的互連)
  • 設(shè)備在系統(tǒng)中的類別描述(類別包括磁盤,分區(qū)等等)

在2.5內(nèi)核中,與設(shè)備驅(qū)動(dòng)程序相關(guān)的其他發(fā)展包括:

  • 不再使用 malloc.h。所有包含 <linux/malloc.h>(用于內(nèi)存分配)的代碼現(xiàn)在要替換為 <linux/slab.h>。
  • 用于 x86 體系結(jié)構(gòu)的 HZ 值增加到1000。引入了一個(gè)叫做 jiffies_64 的瞬間計(jì)算器,以避免由于 HZ 值的變化而引起瞬間變量的迅速溢出。
  • 引入了一個(gè)叫做 ndelay() 的新的延遲函數(shù),允許納秒級(jí)的等待。
  • 引入了一個(gè)叫做 seqlock() 的新類型的鎖,用于鎖定小段的經(jīng)常被訪問的數(shù)據(jù)(不是指針)。
  • 由于2.6內(nèi)核可以搶占,應(yīng)該在驅(qū)動(dòng)程序中使用 preempt_disable() 和 preempt_enable(),從而保護(hù)代碼段不被搶占(禁止 IRQ 同時(shí)也就隱式地禁止了搶占)。
  • 在2.5中加入了異步 I/O。這意味著用戶進(jìn)程可以同時(shí)進(jìn)行多個(gè) I/O 操作,而不用等待它們完成。在字符驅(qū)動(dòng)程序中引入了異步 API。
  • 塊層在2.5的開發(fā)過程中經(jīng)歷了大幅度的變化。這意味著原來用于2.4的塊設(shè)備需要進(jìn)行重新設(shè)計(jì)。
  • 在2.5中引入了sys文件系統(tǒng),它給出了系統(tǒng)的設(shè)備模型的用戶空間描述。它掛載在 /sys 目錄下。




回頁(yè)首


結(jié)束語(yǔ)

由于相對(duì)于2.4來說 Linux2.6發(fā)生了太多的變化,所以在 Linux 內(nèi)核界有一種說法是新的發(fā)布版本應(yīng)該命名為3.0。Linus 將最終決定如何命名,官方可能將于2003年11月發(fā)布官方版本。不管最終采用哪個(gè)版本號(hào),相對(duì)于2.4來說,新的內(nèi)核發(fā)布版本在多種平臺(tái)和體系結(jié)構(gòu)上性 能將更快,可擴(kuò)展性更強(qiáng),更加穩(wěn)定。

Linus 已經(jīng)邀請(qǐng)世界各地的測(cè)試人員來查找 bug 和報(bào)告問題,并要求發(fā)行者提供2.6版本的下載。如果您想?yún)⒓?,您可以在下面?參考資料中找到下載和安裝的鏈接。



參考資料



 


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
內(nèi)核如何阻塞與喚醒進(jìn)程?
Linux中Workqueue 機(jī)制分析
linux 中斷機(jī)制淺析
linux源碼分析--進(jìn)程
linux的0號(hào)進(jìn)程和1號(hào)進(jìn)程
linux kernel 工作隊(duì)列
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服