第1章 Linux內核簡介
用戶界面是操作系統的外在表象,內核纔是操作系統的內在覈心。
內核有時候被稱作是超級管理者或者是操作系統核心。
應用程序被稱爲通過系統調用在內核空間運行,而內核被稱爲運行於進程上下文中。
運行於內核空間,處於進程上下文,代表某個特定的進程執行。
運行於內核空間,處於中斷上下文,與任何進程無關,處理某個特定的中斷。
運行於用戶空間,執行用戶進程。
Unix內核幾乎毫無例外的都是一個不可分割的靜態可執行塊(文件)。
Linux是一個單內核。Linux內核運行在單獨的內核地址空間 ,不過,Linux汲取了微內核的精華:其引以爲豪的是模塊化設計、搶佔式內核、支持內核線程以及動態裝載內核模塊的能力。
第2章 從內核出發
安裝內核源代碼:
tar xvjf linux-x.y.z.tar.bz2
tar xvzf linux-x.y.z.tar.gz
Makeflie是Makefile內核的基礎
make config
make menuconfig
make xconfig
make gconfig
maek>../some_other_file
make>/dev/null
make modules install
內核編程時必須使用GNU C
內核代碼中所用到的C語言擴展中讓感興趣的那部分:內聯函數,內聯彙編,分支聲明
沒有內存保護機制
不要輕易在內核中使用浮點數
容積小而固定的棧
同步和併發
可移植性的重要性
內核的確是一頭獨一無二的猛獸:沒有內存保護,沒有靠得住的libc,小的堆棧,龐大的源碼樹。Linux內核遵循它自己的遊戲規則,以大人物的架勢運行,運行足夠長的時間後才停止,打破了慣以爲常的習俗。
第3章 進程管理
進程是Unix操作系統最基本的抽象之一。
內核調度的對象是線程,而不是進程。
Linux系統的線程實現非常特別——它對線程和進程並不特別區分。對Linux而言,線程只不過是一種特殊的進程罷了。
進程是處於執行期的程序以及它所包含的資源的總稱。
fork()和exit()
內核把進程存放在叫做任務隊列的雙向循環鏈表中。
Linux通過slab分配器分配task_struct結構,這樣能達到對象複用和緩存着色的目的。
內核通過一個惟一的進程標識符或PID來標識每個進程。
進程描述符中的state域描述了進程的當前狀態。
內核經常需要調整某個進程的狀態。這時最好使用set_task(task,state)函數。該函數將指定的進程設置爲指定的狀態。
進程上下文。進程家族樹。
傳統的fork()系統調用直接把所有的資源複製給新創建的進程。
Linux通過clone()系統調用實現fork()。
vfork()系統調用和fork()的功能相同,除了不拷貝父進程的頁表項。
線程機制是現代編程技術中常用的一種抽象。
新建的進程和它的父線程就是流行的所謂線程。
內核經常需要在後臺執行一些操作。這種任務可以通過內核線程完成——獨立運行在內核空間的標準進程。內核線程和普通的進程間的區別在於內核線程沒有獨立的地址空間。它們只在內核空間運行,從來不切換到用戶空間去。內核進程和普通進程一樣,可以被調度,也可以被搶佔。
一般說來,進程的析構發生在它調用exit()之後,即可能顯式地調用這個系統調用,也可能隱式地從某個程序的主函數返回。
在調用了do_exita()之後,儘管線程已經僵死不能再運行了,但是系統還保留了它的進程描述符。當最終需要釋放進程描述符時,release_task()會被調用。
如果父進程在子進程之前退出,必須有機制來保證子進程能找到一個新的父親,否則的話這些成爲孤兒的進程就會在退出時永遠處於僵死狀態,白白的耗費內存。
第4章 進程調度
調度程序是內核的組成部分,它負責選擇下一個要運行的進程。
多任務操作系統就是能同時併發地交互執行多個進程的操作系統。
多任務操作系統可以劃分爲兩類:非搶佔式多任務和搶佔式多任務。
搶佔和讓步
策略決定調度程序在何時讓什麼進程運行。
進程可以被分爲I/O消耗型和處理器消耗型。
調度算法中最基本的一類就是基於優先級的調度。
Linux內核提供了兩組獨立的優先級範圍:第一種是nice值,第二個範圍是實時優先級。
時間片是一個數值,它表明進程在被搶佔前所能持續運行的時間。
進程並不是一定非要一次就用完它所有的時間片。
Linux系統是搶佔式的。
Linux的調度程序定義於kernel/sched.c中。
調度程序中最基本的數據結構是運行隊列。可執行隊列定義於kernel/sched.c中。
每個運行隊列都有兩個優先級數組,一個活躍的和一個過期的。
每個優先級數組都要包含一個這樣的位圖成員,至少爲每個優先級準備一位。
選定一個進程並切換到它去執行是通過schedule()函數實現的。
進程擁有一個初始的優先級,叫做nice值。
休眠(被阻塞)的進程處於一個特殊的不可執行狀態。
負載平衡程序由kernel/sched.c中的函數load_balance()來實現。
上下文切換,也就是從一個可執行進程切換到另一個可執行進程,由定義在kernel/sched.c中的context_switch()函數負責處理。
Linux完整地支持內核搶佔。
只要沒有持有鎖,內核就可以進行搶佔。
Linux提供了兩種實時調度策略:SCHED_FIFO和SCHED_RR
sched_setscheduler()和sched_getscheduler()分別用於設置和獲取進程的調度策略和實時優先級。
Linux調度程序提供強制的處理器綁定機制。
第5章 系統調用
爲了和用戶空間上運行的進程進行交互,內核提供了一組接口。透過該接口,應用程序可以訪問硬件設備和其他操作系統資源。這組接口在應用程序和內核之間扮演了使者的角色,應用程序發送各種請求,而內核負責滿足這些請求。實際上提供這組接口主要是爲了保證系統穩定可靠,避免應用程序恣意妄行,惹出大麻煩。
API、POSIX和C庫
一般情況下,應用程序通過應用編程接口而不是直接通過系統調用來編程。
在Unix世界中,最流行的應用編程接口是基於POSIX標準的。
提供機制而不是策略。
系統調用通常通過函數進行調用。
每個系統調用被賦予一個系統調用號。
應用程序應該以某種方式通知系統,告訴內核自己需要執行一個系統調用,希望系統切換到內核態,這樣內核就可以代表應用程序來執行系統調用了。
設計接口的時候要儘量爲將來多做考慮。
系統調用必須仔細檢查它們所有參數是否合法有效。
copy_to_user()和copy_from_user()都有可能引起阻塞。
內核在執行系統調用的時候處於進程上下文。
系統調用靠C庫支持。
第6章 中斷和中斷處理程序
中斷使得硬件得以與處理器進行通信。
中斷本質上是一種特殊的電信號,由硬件設備發向處理器。處理器接收到中斷後,會馬上向操作系統反映此信號的到來,然後就由OS負責處理這些新到來的數據。
內核隨時可能因爲新到來的中斷而被打斷。
不同的對應的中斷不同,而每個中斷都通過一個惟一的數字標識。
這些中斷值通常被稱爲中斷請求線(IRQ)
異常與中斷不同,它在產生時必須考慮與處理器時鐘同步。實際上,異常也常常稱爲同步中斷。
在響應一個特定中斷的時候,內核會執行一個函數,該函數叫做中斷處理程序或中斷服務例程。
中斷上下文,中斷處理程序是上半部。
中斷處理程序是管理硬件的驅動程序的組成部分 int request_irq(...)
卸載驅動程序時,需要註銷相應的中斷處理程序,並釋放中斷線。void free_irq(unsigned int irq,void *dev_id)
當執行一箇中斷處理程序或下半部時,內核處於中斷上下文中。進程上下文是一種內核所處的操作模式。
中斷處理系統在Linux中的實現是非常依賴於體系結構的,想必你對此不會感動特別驚訝。
Linux內核提供了一組接口用於操作機器上的中斷狀態。
第7章 下半部和推後執行的工作
下半部的任務就是執行與中斷處理密切相關但中斷處理程序本身不執行的工作。
以後僅僅用來強調不是馬上而已,理解這一點相當重要。
和上半部分只能通過中斷處理程序實現不同,下半部可以通過多種機制實現。
BH,任務隊列,軟中斷。
軟中斷保留給系統中對時間要求最嚴格以及最重要的下半部使用。
taskle是利用軟中斷實現的一種下半部機制。
一般單純禁止下半部的處理是不夠的。爲了保證共享數據的安全,更常見的做法是先得到一個鎖然後再禁止下半部的處理。
內核同步介紹:共享內存的應用程序必須特別留意保護共享資源,防止共享資源被併發訪問。
第8章 內核同步介紹
所謂臨界區就是訪問和操作共享數據的代碼段。多個執行線程併發訪問同一個資源通常是不安全的,爲了避免在臨界區中併發訪問,編程者必須保證這些代碼原子地執行
避免併發和防止競爭條件被稱爲同步。
鎖的使用是自願的、非強制性的,它完全屬於一種編程者自選的編程手段。
用戶空間之所以需要同步,是因爲用戶程序會被調度程序搶佔和重新調度。
在中斷處理程序上能避免併發訪問的安全代碼稱作中斷安全碼
預防死鎖的規則:加鎖的順序是關鍵。防止發生飢餓。不要重複請求一個鎖。越複雜的加鎖方案有可以會造成死鎖--設計應力求簡單。
第9章 內核同步方法
原子操作可以保證指令以原子的方式執行——執行過程不被打斷。
內核提供了兩組原子操作接口——一組針對整數進行操作,另一組針對單獨的位進行操作。
針對整數的原子操作只能對atomic_t類型的數據進行處理。
使用原子整型操作需要的聲明都在<asm/atomic.h>文件中。
原子操作通常是內聯函數,往往是通過內嵌彙編指令來實現的。
自旋鎖最多隻能被一個可執行線程持有。如果一個執行線程試圖獲得一個被爭用的自旋鎖,那麼該線程就會一直進行忙循環——旋轉——等待鎖重新可用。
警告:自旋鎖是不可遞歸的。
自旋可以使用在中斷處理程序中。
使用鎖的時候一定要對症下藥,要有針對性。要知道需要保護的是數據而不是代碼。
既然不是對代碼加鎖,那就一定要用特定的鎖來保護自己的共享數據。
spin_lock_init()用來初始化動態創建的自旋鎖。
一個或多個讀任務可以併發的持有讀者鎖;相反,用於寫的鎖最多隻能被一個寫任務持有,而且此時不能有併發的讀操作。有時把讀/寫鎖叫做共享/排斥鎖,或者併發/排斥鎖。
Linux中的信號量是一種睡眠鎖
信號量不同於自旋鎖,它不地禁止內核搶佔,所以持有信號量的代碼可以被搶佔。這意味着信號量不會對調度的等待時間帶來負面影響。
信號量的實現是與體系結構相關的,具體實現定義在文件<asm/semaphore.h>中。
與自旋鎖一樣,信號量也有區分讀-寫訪問的可能。與讀-寫自旋鎖和普通自旋鎖之間的關係差不多,讀-寫信號量也要比普通信號量更具優勢。
BKL(大內核鎖)是一個全局自旋鎖,使用它主要是爲了方便實現從Linux最初的SMP過渡到細粒度加鎖機制。
Seq鎖提供了一種很簡單的機制,用於讀寫共享數據。
可以通過preempt_disable()禁止內核搶佔。
第10章 定時器和時間管理
時間管理在內核中佔有非常重要的地位。
系統定時器是一種可編程硬件芯片,它能以固定頻率產生中斷。該中斷就是所謂的定時器中斷,它所對應的中斷處理程序負責更新系統時間,還負責執行需要週期性運行的任務。
系統定時器和時鐘中斷處理程序是Linux系統內核管理機制中的中樞。
事實上內核必須在硬件的幫助下才能計算和管理時間。
系統定時器以某種頻率自行觸發或射中時鐘中斷,該頻率可以通過編程預定,稱作節拍率。
內核知道連續兩次時鐘中斷的間隔時間。這個間隔時間就稱爲節拍,它等於節拍率分之一。
內核通過控制時鐘中斷維護實際時間。
系統定時器頻率是通過靜態預處理定義的,也就是HZ(赫茲)
編寫內核代碼時,不要認爲HZ值是一個固定不變的值。
操作系統並非一定需要固定的時鐘中斷。
全局變量jiffies用來記錄自系統啓動以來產生的節拍的總數。
系統運行時間以秒爲單位計算,就等於jiffies/HZ
jiffies變量總是無符號長整數,
如果改變內核中HZ的值會給用戶空間中某些程序造成異常結果。
實時時鐘(RTC)是用來持久存放系統時間的設備,即使系統關閉後,它也可以靠主板上的微型電池提供的電力保持系統的計時。
update_one_process()函數的作用是更新進程時間。
當前實際時間(牆上時間)定義在文件kernel/timer.c中。
讀寫xtime變量需要使用xtime_lock鎖,該鎖不是普通自旋鎖而是一個seqlock鎖。
定時器——有時也稱爲動態定時器或內核定時器——是管理內核時間的基礎
因爲定時器與當前執行代碼是異步的,因此就有可能存在潛在的競爭條件。
內核在時鐘中斷髮生後執行定時器,定時器作爲軟中斷在下半部上下文中執行。
最簡單的延遲方法是忙等待(或者說忙循環)
<linux/jiffies.h>中jiffies變量被標記爲關鍵字volatile,關鍵字volatile指示編譯器在每次訪問變量時都重新從主內存中獲得,而不是通過寄存器中的變量別名來訪問。
更理想的延遲執行方法是使用schedule_timeout()函數,該方法會讓需要延遲執行的任務睡眠到指定的延遲時間耗盡後再重新運行。
第11章 內存管理
內核把物理頁作爲內存管理的基本單位。儘管處理器的最小可尋址單位通常爲字,但是,內存管理單元通常以頁爲單位進行處理。
MMU(內存管理單元)以頁大小爲單位來管理系統中的頁表。
內核用struct_page結構表示系統中的每個物理頁,該結構位於<linux/mm.h>中,flag域用來存放頁的狀態。
Linux把系統的頁劃分爲區,形成不同的內存池,這樣就可以根據用途進行分配了。
所有這些接口都以頁爲單位分配內存,定義於<linux/gfp.h>中。最核心的函數是: struct page * alloc_page(unsigned int gfp_mask,unsigned int order)
可以獲得填充爲0的頁。
可以翻譯頁,有三個函數可用 分別爲
void _free_pages(struct page *page,unsigned int order)
void free_pages(unsigned long addr,unsigned int order)
void free_page(unsigned long addr)
kmalloc()函數一個簡單的接口,用它可以獲得以字節爲單位的一塊內核內存。
行爲修飾符、區修飾符及類型。
kmalloc()的另外一端就是kfree()
vmalloc()函數的工作方式類似於kmalloc(),只不過前者分配的內存虛擬地址是連續的,而物理地址則無需連續。
分配和釋放數據結構是所有內核中最普通的操作之一。
當必須創建一個映射而當前上下文又不能睡眠時,內核提供了臨時映射
支持SMP的現代操作系統使用每個CPU上的數據,對於給定的處理器其數據是惟一的。
第12章 虛擬文件系統
虛擬文件子系統作爲內核子系統,爲用戶空間程序提供了文件系統相關的接口。系統中所有文件系統不但依賴VFS共存,而且也依靠VFS系統協同工作。
VFS使得用戶可以直接使用open(),read(),write()這樣的系統調用而無需考慮具體文件系統和實際物理介質。
VFS提供了一個通用文件系統模型,該模型囊括了我們所能想到的文件系統的常用功能和行爲。
文件,目錄項,索引節點和安裝點。
從本質上講文件系統是特殊的數據分層存儲結構,它包含文件、目錄和相關的控制信息。
文件的相關信息,有時被稱作爲文件的元數據(也就是說,文件的相關數據),被存儲在一個單獨的數據結構中,該結構被稱爲索引節點,它其實是index node的縮寫,不過近來術語 “inode”使用得更爲普遍一些。
VFS其實採用的是面向對象的設計思路,使用一族數據結構來代表通用文件對象。
VFS中有四個主要的對象類型:超級塊對象,索引節點對象,目錄項對象,文件對象。
各種文件系統都必須實現超級塊,該對象用於存儲特定文件系統的信息,通常對於存放在磁盤特定扇區中的文件系統超級塊或文件系統控制塊。
超級塊對象由super_block結構體表示,定義在文件<linux/fs.h>。
索引節點對象包含了內核在操作文件或目錄時需要的全部信息。索引節點對象由inode結構體表示,定義在文件<linux/fs.h>中。
目錄項對象,VFS把目錄當作文件對待,所以在路徑/bin/vi中,bin和vi都屬於文件。
目錄項對象有三種有效狀態:被使用,未被使用和負狀態。
VFS的最後一個主要對象是文件對象。文件對象表示進程已打開的文件。如果我們站在用戶空間來看待VFS,文件對象會首先進入我們的視野。
文件對象由file結構體表示,定義在文件<linux/fs.h>中。
文件對象的操作由file_operations結構體表示,定義在文件<linux/fs.h>中。
系統中的每一個進程都有自己的一組打開的文件,像根文件系統、當前工作目錄、安裝點等等。有三個數據結構將VFS層和系統的進程緊密聯繫在一起,它們分別是:files_struct、fs_struct和namespace結構體。
Linux支持了相當多種類的文件系統。從本地文件系統,如ext2和ext3,到網絡文件系統,如NFS和Coda,Linux在標準內核中已支持的文件系統超過50種。
第13章 塊I/O層
系統中能夠隨機訪問固定大小數據片的設備被稱作塊設備,這些數據片就稱作塊。最常見的塊設備就是硬盤。
另一種基本的設備類型是字符設備。
這兩種類型的設備的根本區別在於它們是否可以被隨機訪問——換句話說,就是能否在訪問設備時隨意地從一個位置跳轉到另一個位置。
塊設備中最小的可尋址單元是扇區。
描述符用buffer_head結構體表示,被稱作緩衝區頭,在文件<linux/buffer_head.h>中。
目前內核中塊I/O操作的基本容器由bio結構體表示,它定義在文件<linux/bio.h>中。
塊設備將它們掛起的塊I/O請求保存在請求隊列中,該隊列由request_queue結構體表示,定義在文件<linux/blkdev.h>中,包含一個雙向請求鏈表以及相關控制信息。
爲了優化尋址操作,內核既不會簡單地按請求接收次序,也不會立即將其提交給磁盤。相反,它會在提交前,先執行名爲合併與排序的預操作。
I/O調度程序將磁盤I/O資源分配給系統中所有掛起的塊I/O請求。
第14章 進程地址空間
進程的地址空間,也就是系統中每個用戶空間進程所看到的內存。
進程地址空間由每個進程中的線性地址區組成,而且更爲重要的特點是內核允許進程使用該空間中的地址。
兩個不同的進程可以在它們各自地址空間的相同地址存放不同的數據。
內核使用內存描述符結構體表示進程的地址空間,該結構包含了和進程地址空間有關的全部信息。內存描述符由mm_struct結構體表示,定義在文件<linux/sched.h>中。
在進程描述符中,mm域存放着該進程使用的內存描述符,所以current->mm便指向當前進程的內存描述符。
內核線程沒有進程地址空間,也沒有相關的內存描述符。
當一個進程被調度時,該進程的mm域指向的地址空間被裝載到內存,進程描述符中的active_mm域會被重新,指向新的地址空間。
內存區域由vm_area_struct結構體描述,定義在文件<linux/mm.h>中,內存區域在內核中也經常被稱做虛擬內存區域或VMA。
VMA標誌是一種位標誌,其定義見<linux/mm.h>。
內核使用do_mmap()函數創建一個新的線性地址區間。但是說該函數創建了一個新VMA並不非常準確。
在用戶空間可以通過mmap()系統調用獲取內核函數do_mmap()的功能。
雖然應用程序操作的對象是映射到物理內存之上的虛擬內存。
第15章 頁高速緩存和頁回寫
頁高速緩存是Linux內核實現的一種主要磁盤緩存。它用來減少對磁盤的I/O操作。
頁高速緩存是由RAM中的物理頁組成的,緩存中每一頁都對應着磁盤中的多個塊。每當內核開始執行一個頁I/O操作時,首先會檢查需要的數據是否在高速緩存中,如果在,那麼內核就直接使用高速緩存中的數據,從而避免訪問磁盤。
頁高速緩存緩存的是頁面。
一個物理頁可能由多個不連續的物理磁盤塊組成。
Linux頁高速緩存使用address_space結構體描述頁高速緩存中的頁面。該結構體定義在文件<linux/fs.h>中。
其中i_mmap字段是一個優先搜索樹。
頁高速緩存通過兩個參數——address_space對象和一個偏移量——進行搜索。每個address_space對象都有惟一的基樹,它保存在page_tree結構體中。
膝上型電腦模式是一種特殊的頁回寫策略,該策略主要意圖是將硬盤轉動的機械行爲最小化,允許硬盤儘可能長時間的停滯。
pdflush線程的工作是分別由bdflush和kupdated兩個線程共同完成。
第16章 模塊
儘管Linux是“單塊內核”的操作系統——也是說整個系統內核都運行於一個單獨的保護域中。但是Linux內核是模塊化組成的,它允許內核在運行時動態地向其中插入或從中刪除代碼。
模塊的所有初始化函數必須符合下面的形式: int my_init(void);
由於採用了新的"kbuild"構建系統,現在構建模塊相比從前更加容易。
編譯後的模塊將被裝入到目錄/lib/modules/version/kernel/下。
Linux模塊之間存在依賴性,也就是說釣魚模塊依賴於魚餌模塊,那麼當載入釣魚模塊時,魚餌模塊會被自動載入。
載入模塊最簡單的方法是通過insmod命令。
所謂存在的Kconfig文件可能是drivers/char/Kconfig.
定義一個模塊參數可通過宏module_param()完成。
模塊被載入後,就會動態連接到了內核。
第17章 kobject和sysfs
統一設備模型,設備模型提供了一個獨立的機制專門來表示設備,並描述其在系統中的拓撲結構。
設備模型的核心部分就是kobject,它由struct kobject結構體表示,定義於頭文件<linux/kobject.h>中。
kobject對象被關聯到一種特殊的類型,即ktype.
kset是kobject對象的集合體。把它看成是一個容器,可將所有相關的kobject對象置於同一位置。
subsystem在內核中代表高層概念,它是一個或多個ksets的大集合。
kobject的主要功能之一就是爲我們提供了一個統一的引用計數功能。
sysfs文件系統中一個處於內存中的虛擬文件系統,它爲我們提供了kobject對象層次結構的視圖。
內核事件層實現了內核到用戶的消息通知系統,就是建立在上文一直討論的kobject基礎之上。
第18章 調試
調試工作艱苦是內核級的開發區別於用戶級開發的一個顯著特點。
如果你沒辦法讓bug重現出來,下面要講的這些步驟就毫無意義。
內核提供的打印函數printk(),和C庫提供的printf()函數功能幾乎相同。
健壯性是printk()函數最容易讓人們接受的一個物質。
printk()和printf()一個最主要的區別就是前者可以指定一個記錄級別。
內核將最重要的記錄等KERN_EMERG定爲“<0>”,將無關緊要的記錄等級“KERN_DEBUG”定爲“<7>”.
怎樣給你的調用的printk()賦記錄等級完全取決於你自己。
在標準的Linux系統上,用戶空間的守護進程klogd從記錄緩衝區中獲取內核消息,再通過syslogd守護進程將它們保存在系統日誌文件中。
oops是內核告知用戶有不幸發生的最常用的方式。
oops的產生有很多可能原因,其中包括內存訪問越界或者非法的指令等。
ksymoops一般會隨Linux發行提供。
託內核搶佔的福,內核提供了一個原子操作計數器。
一些內核調用可以用來方便標記bug,提供斷言並輸出信息。
神奇系統請求鍵是另外一根救命稻草,該功能可以通過定義CONFIG_MAGIC_SYSRQ配置選項來啓用。
可以使用標準的GNU調試器對正運行的內核進行查看。
gdb vmlinux /proc/kcore
gdb kgdb kdb
第19章 可移植性
Linux是一個可移植性非常好的操作系統,它廣泛支持了許多不同體系結構的計算機。可移植性是指代碼從一種體系結構移植到另外一種體系結構上的方便程度。
有些操作系統在設計時把可移植性作爲頭等大事之一。
能夠由機器一次就完成處理的數據被稱爲字。
有些操作系統和處理器不把它們標準字長稱作字,相反,出於歷史原因和某種主頁的命名習慣,它們用字來代表一些固定長度的數據類型。
不透明數據類型隱藏了它們內部格式或結構。在C語言中,它們就像黑盒一樣。支持它們的語言不是很多。作爲替代,開發者們利用typedef聲明一個類型,把它叫做不透明類型。
另外一個不透明數據類型的例子是atomic_t。
C標準表示char類型可以帶符號也可以不帶符號,由具體的編譯器、處理器或由它們兩者共同決定到底char是帶符號合適還是不帶符號合適。
一些體系結構對對齊的要求非常嚴格。通常像基於RISC的系統,載入未對齊的數據會導致處理器陷入。
絕對不要假定時鐘中斷髮生的頻率,也就是每秒產生的jiffies數目。
第20章 補丁、開發和社區
subscribe linux-kernel [email protected] to [email protected]
Linux命名規範:縮進,括號,每行代碼的長度,命名規範,函數,註釋,typedef,