Linux Kernel核心中文手冊--試貼

發表于:2007-07-04來源:作者:點擊數: 標簽:
Linux Kernel核心中文手冊 來自:藍森林自由軟件 Chapter 2 Software Basic( 軟件基礎 ) Linux Kernel核心中文手冊 來自:藍森林自由軟件 Chapter 2 Software Basic( 軟件基礎 ) 程序是用于執行特定任務的計算機指令組合。程序可以用匯編語言,一種非常低級
Linux Kernel核心中文手冊

來自:藍森林自由軟件

Chapter 2

Software Basic( 軟件基礎 )

Linux Kernel核心中文手冊

來自:藍森林自由軟件

Chapter 2

Software Basic( 軟件基礎 )

    程序是用于執行特定任務的計算機指令組合。程序可以用匯編語言,一種非常低級的計算機語言來編寫,也可以使用和機器無關的高級語言,比如 C 語言編寫。操作系統是一個特殊的程序,允許用戶通過它運行應用程序,比如電子表和文字處理等等。本章介紹了基本的編程原理,并簡介操作系統的目的和功能。

2.1 Computer Languages( 計算機語言 )

2.1.1. 匯編語言

    CPU 從內存中讀取和執行的指令對于人類來講無法理解。它們是機器代碼,精確的告訴計算機要做什么。比如十六進制數 0x89E5 ,是 Intel 80486 的指令,將寄存器 ESP 的內容拷貝到寄存器 EBP 中。早期計算機中最初的軟件工具之一是匯編程序,它讀入人類可以閱讀的源文件,將其裝配成機器代碼。匯編語言明確地處理對寄存器和對數據的操作,而這種操作對于特定的微處理器而言是特殊的。 Intel X86 微處理器的匯編語言和 Alpha AXP 微處理器的匯編語言完全不同。以下 Alpha AXP 匯編代碼演示了程序可以執行的操作類型:

Ldr r16, (r15) ; 第一行

Ldr r17, 4(r15) ; 第二行

Beq r16,r17,100; 第三行

Str r17, (r15); 第四行

100: ; 第五行

    第一條語句(第一行)將寄存器 15 指定的地址中的內容加載到寄存器 16 中。第二條指令將緊接著的內存中的內容加載到寄存器 17 中。第三行比較寄存器 16 和寄存器 17 ,如果相等,分支到標號 100 ,否則,繼續執行第四行,將寄存器 17 的內容存到內存中。如果內存中的數據相同,就不必存儲數據。編寫匯編級的程序需要技巧而且十分冗長,容易出錯。 Linux 系統的核心很少的一部分是用匯編語言編寫,而這些部分之所以使用匯編語言只是為了提高效率,并且和具體的微處理器相關。

2.1.2 The C Programming Language and Compiler (C 語言和編譯器 )

    使用匯編語言編寫大型程序十分困難,消耗時間,容易出錯而且生成的程序不能移植,只能束縛在特定的處理器家族。更好的選擇是使用和機器無關的語言,例如 C 。 C 允許你用邏輯算法描述程序和要處理的數據。被稱為編譯程序( compiler )的特殊程序讀入 C 程序,并將它轉換為匯編語言,進而產生機器相關的代碼。好的編譯器生成的匯編指令可以和好的匯編程序員編寫的程序效率接近。大部分 Linux 核心是用 C 語言編寫的。以下的 C 片斷:

if (x != y)

x = y;

    執行了和前面示例中匯編代碼完全一樣的操作。如果變量 x 的內容和變量 y 的內容不一樣,變量 y 的內容被拷貝到變量 x 。 C 代碼用例程( routine )進行組合,每一個例程執行一項任務。例程可以返回 C 所支持的任意的數值或數據類型。大型程序比如 Linux 核心分別由許多的 C 語言模塊組成,每一個模塊有自己的例程和數據結構。這些 C 源代碼模塊共同構成了邏輯功能比如文件系統的處理代碼。

   C 支持多種類型的變量。一個變量是內存中的特定位置,可用符號名引用。上述的 C 片斷中, x 和 y 引用了內存中的位置。程序員不需要關心變量在內存中的具體位置,這是連接程序(下述)必須處理的。一些變量包含不同的數據例如整數、浮點數等和另一些則包含指針。

    指針是包含其它數據在內存中的地址的變量。假設一個變量 x ,位于內存地址 0x80010000 , 你可能有一個指針 px ,指向 x 。 Px 可能位于地址 0x80010030 。 Px 的值則是變量 x 的地址, 0x80010000 。

C 允許你將相關的變量集合成為結構。例如:

Struct {

Int I;

Char b;

} my_struct;

是一個叫做 my_struct 的數據結構,包括兩個元素:一個整數( 32 位) I 和一個字符( 8 位數據) b 。

2.1.3 Linkers (連接程序)

    連接程序將幾個目標模塊和庫文件連接在一起成為一個單獨的完整程序。目標模塊是匯編程序或編譯程序的機器碼輸出,它包括機器碼、數據和供連接程序使用的連接信息。比如:一個目標模塊可能包括程序的所有數據庫功能,而另一個目標模塊則包括處理命令行參數的函數。連接程序確定目標模塊之間的引用關系,即確定一個模塊所引用的例程和數據在另一個模塊中的實際位置。 Linux 核心是由多個目標模塊連接而成的獨立的大程序。

2.2 What is an Operating System (什么是操作系統?)

    沒有軟件,計算機只是一堆發熱的電子元件。如果說硬件是計算機的心臟,則軟件就是它的靈魂。操作系統是允許用戶運行應用程序的一組系統程序。操作系統將系統的硬件抽象,呈現在用戶和應用程序之前的是一個虛擬的機器。是軟件造就了計算機系統的特點。大多數 PC 可以運行一到多個操作系統,而每一個操作系統從外觀和感覺上都大不相同。 Linux 由不同功能的部分構成,這些部分總體組合構成了 Linux 操作系統。 Linux 最明顯的部分就是 Kernel 自身,但是如果沒有 shell 或 libraries 一樣沒有用處。

    為了了解什么是操作系統,看一看在你輸入最簡單的命令時發生了什么:

$ls

Mail c images perl

Docs tcl

$

    這里的 $ 是登錄的 shell 輸出的提示符(此例是 bash ):表示 shell 在等候你(用戶)輸入命令。輸入 ls 引發鍵盤驅動程序識別輸入的字符,鍵盤驅動程序將識別的字符傳遞給 shell 去處理。 shell 先查找同名的可執行映象,它找到了 /bin/ls, 然后調用核心服務將 ls 執行程序加載到虛擬內存中并開始執行。 ls 執行程序通過執行核心的文件子系統的系統調用查找文件。文件系統可能使用緩存的文件系統信息或通過磁盤設備驅動程序從磁盤上讀取文件信息 , 也可能是通過網絡設備驅動程序同遠程主機交換信息而讀取本系統所訪問的遠程文件的詳細信息(文件系統可以通過 NFS 網絡文件系統遠程安裝)。不管文件信息是如何得到的, ls 都將信息輸出,通過顯示驅動程序顯示在屏幕上。

    以上的過程看起來相當復雜,但是它說明了即使是最簡單的命令也是操作系統各個功能模塊之間共同協作的結果,只有這樣才能提供給你(用戶)一個完整的系統視圖。

2.2.1 Memory management (內存管理)

    如果擁有無限的資源,例如內存,那么操作系統所必須做的很多事情可能都是多余的。所有操作系統的一個基本技巧就是讓少量的物理內存工作起來好像有相當多的內存。這種表面看起來的大內存叫做虛擬內存,就是當軟件運行的時候讓它相信它擁有很多內存。系統將內存分為容易處理的頁,在系統運行時將這些頁交換到硬盤上。而應用軟件并不知道,因為操作系統還使用了另一項技術:多進程。

2.2.2 Processes ( 進程 )

    進程可以看作一個在執行的程序,每一個進程都是正在運行的特定的程序的獨立實體。如果你觀察一下你的 Linux 系統,你會發現有很多進程在運行。例如:在我的系統上輸入 ps 顯示了以下進程:

$ ps

PID TTY STAT TIME COMMAND

158 pRe 1 0:00 -bash

174 pRe 1 0:00 sh /usr/X11R6/bin/startx

175 pRe 1 0:00 xinit /usr/X11R6/lib/X11/xinit/xinitrc --

178 pRe 1 N 0:00 bowman

182 pRe 1 N 0:01 rxvt -geometry 120x35 -fg white -bg black

184 pRe 1 < 0:00 xclock -bg grey -geometry -1500-1500 -padding 0

185 pRe 1 < 0:00 xload -bg grey -geometry -0-0 -label xload

187 pp6 1 9:26 /bin/bash

202 pRe 1 N 0:00 rxvt -geometry 120x35 -fg white -bg black

203 ppc 2 0:00 /bin/bash

1796 pRe 1 N 0:00 rxvt -geometry 120x35 -fg white -bg black

1797 v06 1 0:00 /bin/bash

3056 pp6 3 < 0:02 emacs intro/introduction.tex

3270 pp6 3 0:00 ps

$

    如果我的系統擁有多個 CPU 那么每個進程可能(至少在理論上如此)都在不同的 CPU 上運行。不幸的是,只有一個,所以操作系統又使用技巧,在短時間內依次運行每一個進程。這個時間段叫做時間片。這種技巧叫做多進程或調度,它欺騙了每一個進程,好像它們是唯一的進程。進程相互之間受到保護,所以如果一個進程崩潰或不能工作,不會影響其他進程。操作系統通過給每一個進程一個獨立的地址空間來實現保護,進程只能訪問它自己的地址空間。

2.2.3 Device Drivers (設備驅動程序)

    設備驅動程序組成了 Linux 核心的主要部分。象操作系統的其他部分一樣,它們在一個高優先級的環境下工作,如果發生錯誤,可能會引發嚴重問題。設備驅動程序控制了操作系統和它控制的硬件設備之間的交互。比如:文件系統向 IDE 磁盤寫數據塊是使用通用塊設備接口。驅動程序控制細節,并處理和設備相關的部分。設備驅動程序和它驅動的具體的控制器芯片相關,所以,如果你的系統有一個 NCR810 的 SCSI 控制器,那么你需要 NCR810 的驅動程序。

2.2.4 The Filesystems (文件系統)

    象 Unix 一樣,在 Linux 里,系統對獨立的文件系統不是用設備標示符來存?。ū热珧寗悠骶幪柣蝌寗悠髅Q),而是連接成為一個樹型結構。 Linux 在安裝新的文件系統時,把它安裝到指定的安裝目錄,比如 /mnt/cdrom ,從而合并到這個單一的文件系統樹上。 Linux 的一個重要特征是它支持多種不同的文件系統。這使它非常靈活而且可以和其他操作系統良好共存。 Linux 最常用的文件系統是 EXT2 ,大多數 Linux 發布版都支持。

    文件系統將存放在系統硬盤上的文件和目錄用可以理解的統一的形式提供給用戶,讓用戶不必考慮文件系統的類型或底層物理設備的特性。 Linux 透明的支持多種文件系統(如 MS-DOS 和 EXT2 ),將所有安裝的文件和文件系統集合成為一個虛擬的文件系統。所以,用戶和進程通常不需要確切知道所使用的文件所在的文件系統的類型,用就是了。

    塊設備驅動程序掩蓋了物理塊設備類型的區別(如 IDE 和 SCSI )。對于文件系統來講,物理設備就是線性的數據塊的集合。不同設備的塊大小可能不同,如軟驅一般是 512 字節,而 IDE 設備通常是 1024 字節,同樣,對于系統的用戶,這些區別又被掩蓋。 EXT2 文件系統不管它用什么設備,看起來都是一樣的。

2.3 Kernet Data Structures (核心數據結構)

    操作系統必須紀錄關于系統當前狀態的許多信息。如果系統中發生了事情,這些數據結構就必須相應改變以反映當前的實際情況。例如:用戶登錄到系統中的時候,需要創建一個新的進程。核心必須相應地創建表示此新進程的數據結構,并和表示系統中其他進程的數據結構聯系在一起。

    這樣的數據結構多數在物理內存中,而且只能由核心和它的子系統訪問。數據結構包括數據和指針(其他數據結構或例程的地址)。乍一看, Linux 核心所用的數據結構可能非?;靵y。其實,每一個數據結構都有其目的,雖然有些數據結構在多個的子系統中都會用到,但是實際上它們比第一次看到時的感覺要簡單的多。

    理解 Linux 核心的關鍵在于理解它的數據結構和核心處理這些數據結構所用到的大量的函數。本書以數據結構為基礎描述 Linux 核心。論及每一個核心子系統的算法,處理的方式和它們對核心數據結構的使用。

2.3.1 Linked Lists (連接表)

    Linux 使用一種軟件工程技術將它的數據結構連接在一起。多數情況下它使用鏈表數據結構。如果每一個數據結構描述一個物體或者發生的事件的單一的實例,比如一個進程或一個網絡設備,核心必須能夠找出所有的實例。在鏈表中,根指針包括第一個數據結構或單元的地址,列表中的每一個數據結構包含指向列表下一個元素的指針。最后元素的下一個指針可能使 0 或 NULL ,表示這是列表的結尾。在雙向鏈表結構中,每一個元素不僅包括列表中下一個元素的指針,還包括列表中前一個元素的指針。使用雙向鏈表可以比較容易的在列表中間增加或刪除元素,但是這需要更多的內存存取。這是典型的操作系統的兩難情況:內存存取數還是 CPU 的周期數。

2.3.2 Hash Tables

    鏈接表是常用的數據結構,但是游歷鏈接表的效率可能并不高。如果你要尋找指定的元素, 可能必須查找完整個表才能找到。 Linux 使用另一種技術: Hashing 來解決這種局限。 Hash table 是指針的數組或者說向量表。數組或向量表是在內存中依次存放的對象。書架可以說是書的數組。數組用索引來訪問,索引是數組中的偏移量。再來看書架的例子,你可以使用在書架上的位置來描述每一本書:比如第 5 本書。

    Hash table 是一個指向數據結構的指針的數組,它的索引來源于數據結構中的信息。如果你用一個數據結構來描述一個村莊的人口,你可以用年齡作為索引。要找出一個指定的人的數據,你可以用他的年齡作為索引在人口散列表中查找,通過指針找到包括詳細信息的數據結構。不幸的是,一個村莊中可能很多人年齡相同,所以散列表的指針指向另一個鏈表數據結構,每一個元素描述同齡人。即使這樣,查找這些較小的鏈表仍然比查找所有的數據結構要快。

    Hash table 可用于加速常用的數據結構的訪問,在 Linux 里常用 hash table 來實現緩沖。緩沖是需要快速存取的信息,是全部可用信息的一個子集。數據結構被放在緩沖區并保留在那里,因為核心經常訪問這些結構。使用緩沖區也有副作用,因為使用起來比簡單鏈表或者散列表更加復雜。如果數據結構可以在緩沖區找到(這叫做緩沖命中),那么一切很完美。但是如果數據結構不在緩沖區中,那么必須查找所用的相關的數據結構,如果找到,那么就加到緩沖區中。增加新的數據結構到緩沖區中可能需要廢棄一個舊的緩沖入口。 Linux 必須決定廢棄那一個數據結構,風險在于廢棄的可能使 Linux 下一個要訪問的數據結構。

2.3.3 Abstract Interfaces (抽象接口)

    Linux 核心經常將它的接口抽象化。接口是以特定方式工作的一系列例程和數據結構。比如:所有的網絡設備驅動程序都必須提供特定的例程來處理特定的數據結構。用抽象接口的方式可以用通用的代碼層來使用底層特殊代碼提供的服務(接口)。例如網絡層是通用的,而它由底層符合標準接口的同設備相關的代碼提供支持。

    通常這些底層在啟動時向高一層登記。這個登記過程常通過在鏈接表中增加一個數據結構來實現。例如,每一個連結到核心的文件系統在核心啟動時進行登記(或者如果你使用模塊,在文件系統第一次使用時向核心登記)。你可以查看文件 /proc/filesystems 來檢查那些文件系統進行了登記。登記所用的數據結構通常包括指向函數的指針。這是執行特定任務的軟件函數的地址。再一次用文件系統登記的例子,每一個文件系統登記時傳遞給 Linux 核心的數據結構都包括一個和具體文件系統相關的例程地址,在安裝文件系統時必須調用。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97