tipi 深入理解php内核 pdf_大牛的学习笔记-深入理解Linux内核(完整版)
第一章、緒論
1.Unix文件可以是下列類型之一:
a.正規文件(regular file)
b.目錄(directroy)
c.符號鏈(symbolic link)
d.塊設備文件(block-oriented device file)
e.字符設備文件(charactor-oriented device file)
f.管道(pipe)命名管道(named pipe)(即FIFO)
h.套接字(socket)
2.內核分配給進程的虛擬地址空間由以下內存區域組成:
a.程序的可執行代碼
b.程序的初始化數據
c.程序的未初始化數據
d.初始程序棧(即用戶態棧)
e.需要共享的庫的可執行代碼和數據
f.堆(由程序動態請求的內存)
3.設備驅動程序
內核通過設備驅動程序(device driver)與I/O設備打交道。設備驅動程序包含在內核中,由控制一個或多個設備的數據結構和函數組成。
這些設備包括硬盤、鍵盤、鼠標和監視器等。通過特定的接口,每個驅動程序與內核中的其余部分(甚至與其他驅動程序)相互作用:
優點:
1.可以把特定設備的代碼封裝在特定的模塊中。
2.廠商可以不懂內核代碼,只知道接口規范,就能增加新的設備。
3.內核以統一的方式對待所有的設備,并且通過相同的接口訪問這些設備。
4.可以把設備驅動程序寫成模塊,并動態裝到內核中,不需要重啟系統,不需要的時候可以卸載模塊,
以減少存儲在RAM中的內核映像大小。第三章、進程
1.進程狀態:
a.可運行狀態
b.可中斷狀態
c.不可中斷的等待狀態
d.暫停狀態
e.僵死狀態第四章、進程調度
1.涉及進程調度
a.傳統上把進程分類:
I/O范圍(I/O-bound):頻繁地使用I/O設備,并花費很多時間等待I/O操作的完成。
CPU范圍(CPU-bound):需要大量CPU時間的數值計算應用程序。
b.非傳統分類:
交互式進程:如命令shell、文本編輯程序及圖像應用程序。
批處理進程:如編譯程序、數據庫搜索引擎及科學計算。
實時進程:視頻和音頻應用程序、機器人控制程序及從物理傳感器上收集數據的程序。第五章、內核同步
1.內核同步,內核態進程的非搶占性:
a.在內核態中運行的進程不會被其他進程取代,除非這個進程主動放棄CPU的控制權
b.中斷或異常處理可以中斷在內核態中運行的進程。但是,在中斷處理程序結束時,該進程的內核控制路徑被恢復
c.執行中斷或異常處理的內核控制路徑只能被執行中斷或異常處理的其他內核控制路徑所中斷
2.SMP原子操作 從Intel 80286開始引入lock指令解決這中問題。
lock只是一個用于一條匯編指令之前的特殊字節。當控制單元檢測到一個lock字節時,就鎖定內存總線
這樣其他處理器就不能存取下一條匯編語言指令的目的操作數所指定的內存單元。只有在這條指令執行完成時總線鎖才會被釋放。
因此,帶有lock前綴的讀-修改-寫指令即使在多處理器環境中也是原子的。
3.內核數據結構進行同步訪問的常用方法是使用信號量和自旋鎖。第六章、虛擬文件系統
1.通用文件模型由下列對象類型組成:
a.超級塊對象(superblock object):存放已安裝文件系統的有關信息。對于基于磁盤的文件系統,
這類對象通常對應于存放在磁盤上的文件系統控制塊(filesystem control block)。
b.索引節點對象(inode object):存放關于具體文件的一般信息。對于基于磁盤的文件系統,
這類對象通常對應于存放在磁盤上的文件控制塊(file control block)。
每個索引節點對象都有一個索引節點號,這個號唯一地標識文件系統中的指定文件。
c.文件對象(file object):存放打開文件與進程之間交互的相關信息。這類信息僅當進程訪問文件期間存在于內核內存中。
d.目錄項對象(dentry object):存放目錄項與對應文件進行連接的信息。每個基于磁盤的文件系統都以自己特有的方式將該類信息存在磁盤上。
slab分配高速緩存中。
e.進程->文件對象->目錄項對象->索引節點->(超級塊對象)->磁盤文件。
2.虛擬文件系統,目錄項對象屬于以下四種狀態之一:
a.空閑狀態: 還沒有被VFS使用,對于德內存區由slab分配器進行管理。
b.未使用狀態: 該目錄項對象當前還沒有被內核使用。該對象的引用計數器d_count為NULL。
但其d_indoe域只想相關索引節點。為了必要時回收內存,目錄項包含有效信息,它的內存可能被丟失。
c.正在使用狀態: 該對象被內核使用。d_count的值為正數。目錄項包含有效的信息,并且不能被丟棄。
d.負狀態: 與目錄項相關的索引節點不復存在,那是因為相應的磁盤索引節點已被刪除,d_count域被置NULL。第七章、管理I/O設備
1.三類內存地址:
a.邏輯地址(CPU內部使用)
b.線性地址(CPU內部使用)
c.物理地址(CPU從物理上驅動數據總線所用的內存地址)
d.總線地址(bus address):除CPU之外的硬件設備驅動數據總線所用的內存地址。
2.設備文件(mknod()系統調用來創建設備文件):用來表示Linux所支持的大部分I/O設備的,除了文件名,每個設備文件都還有三個主要屬性。
a.類型(type):塊設備或字符設備
b.主號(major number):從1到255之間的一個數,用以標識設備的類型,通常,具有相同主號和相同類型的所有設備文件共享相同的文件操作集合。
因為他們是由同一設備驅動程序處理的。
c.次號(minor number):在一組主號相同的設備之間唯一標識特定設備所使用的一個數字。
3.沒有對應設備文件的I/O設備
比如網卡:網卡把向外發送的數據放入通往遠程計算機系統的一條線上,把從遠程系統中接受到的報文裝入內核內存。
由于沒有使用文件系統,所以系統管理員必須建立設備名和網絡地址之間的聯系。
應用程序和網絡接口之間的數據通信不是基于標準的有關文件的系統調用。
而是基于socket()、bind()、listen()、accept()和connect()系統調用。
這些系統調用對網絡地址進行操作。這組系統調用由Unix BSD中首先引入,現在已經成為網絡設備的標準變成模型。
4.VFS對設備文件的處理:設備文件也在系統的目錄數中。但它們和正規文件及目錄有根本的不同。當進程訪問正規文件時,
它會通過文件系統訪問磁盤分區的一些
數據塊;而在進程訪問設備文件時,它只要驅動硬件設備就可以了。VFS的責任是為應用程序隱藏設備文件與正規文件之間的差異。
VFS改變打開的設備文件的缺省文件操作。可以把對設備文件的任一系統調用轉換成對設備相關的函數的調用,而不是對主文件系統對于函數的調用。
設備相關的函數對硬件設備進行操作以完成進程所請求的操作。
驅動程序:控制I/O設備的一組相關的函數稱為設備驅動程序(device driver)。由于每個設備都有一個唯一的I/O控制器,因此也就有唯一的
命令和唯一的狀態信息,所以大部分I/O設備類型都有自己的驅動程序。
5.設備文件調用open()函數執行的操作:
a.如果設備驅動程序被包含在一個內核模塊中,那么把引用計數器的值加1,以便只有把設備文件關閉之后才能卸載這個模塊。
b.如果設備驅動程序要處理多個同類型的設備,那么就是用次號來選擇合適的驅動程序,如果需要,還要使用專門的文件操作表選擇驅動程序。
c.檢查該設備是否真正存在,現在是否正在工作。
d.如果必要,向硬件設備發送一個初始化命令序列。
e.初始化設備驅動程序的數據結構。
6.內核支持的級別
a.根本不支持:應用程序使用設當的in和out匯編語言指令直接與設備的I/O端口進行交互。
b.最小支持:內核不能設別硬件設備,但能識別I/O接口。用戶程序把I/O接口是為能夠讀寫字符流的順序設備。
c.擴展支持:內核設備硬件設備,并處理I/O設備本身,事實上,這種設備可能就沒有對應的設備文件。
7.訪問I/O設備的地址,可以從/proc/ioports文件中獲得。
8.內核對于塊設備的支持特點:
a.通過VFS提供統一接口
b.對磁盤數據進行有效的鏈接
c.為數據提供磁盤高速緩存
9.內核基本上把I/O數據傳送劃分成兩類:
a.緩沖區I/O操作:所傳送的數據保存在緩沖區中,緩沖區是磁盤數據在內核中的普通內存容器。每個緩沖區都和一個特定的塊相關聯
而這個塊由一個設備號和一個塊號來標識
b.頁I/O操作:所傳輸的數據保存在頁框中,每個頁框包含的數據都屬于正規文件。因為沒有必要把這種數據存放在相鄰的磁盤中。
所以就是用文件的索引節點和文件內的偏移量來標識這種數據。主要用于讀取正規文件、文件內存映射和交換。
10.所謂塊(block):就是塊設備驅動程序在一次單獨操作中所傳送的一大塊相鄰字節。
扇區(sector):扇區是硬件設備傳送數據的基本單元。
11.塊設備驅動程序的兩部分:
a.高級驅動程序:處理VFS層。
b.低級驅動程序:處理硬件設備。第八章、訪問正規文件
1.從正規文件讀取數據:generic_file_read()函數實現了大部分文件系統的正規文件的read方法。
2.對正規文件進行預讀:正規文件的預讀需要的算法比物理塊的預讀需要的算法更復雜:
a.由于數據是逐頁進行讀取的,因此預讀算法不必考慮頁內偏移量,只考慮所訪問的頁在文件內部的位置就可以了。
b.當前訪問與上一次訪問不是順序的時,預讀就必須從頭開始重新執行。
c.當進程一直反復地訪問同一頁時(該文件只有很少的一部分被使用),應該減慢預讀的速度甚至停止執行。
d.如果需要,預讀算法必須激活低級I/O設備驅動程序來確保新頁會被讀取。
e.內核通過多次調用一個名為:try_to_read_ahead()的函數來執行預讀操作(read ahead operation),一次預讀一頁。
f.對于每個請求頁,內核都要調用generic_file_readhead()函數,該函數確定是否要執行預讀操作。
3.寫正規文件:write()系統調用會涉及把數據從調用進程的用戶態地址空間中移動到內核數據結構中,然后再移動到磁盤上。
文件對象的write方法允許每種文件類型都定義一個專用的寫操作。
a.寫操作發生時,有效數據是在緩沖區高速緩存中,而不是在頁高速緩存中,更確切地說,當write方法修改了文件的任何部分時。
與這些部分對應的頁高速緩存中的所有頁都不再包含有效數據。一個進程可能認為自己在讀取正確數據,
但是卻沒看到其他進程對這些數據所做的修改。
b.所有基于磁盤的文件系統的write方法都要調用update_vm_cache()函數來修改讀操作所使用的頁高速緩存。
c.通過頁高速緩存對正規文件執行的寫操作,只能用于網絡文件系統。文件的write方法是使用generic_file_write()函數實現。
4.內存映射:一個線性區可以和基于磁盤的文件系統中的一個文件(或者文件的一部分)相關聯。這就是說,內核會把線性區中對一個頁中字節的訪問轉換成
對正規文件中相對于字節的操作,這種技術成為內存映射。
a.共享的:對線性區中的任何寫操作都會修改磁盤上的文件。而且,如果進程對共享內存映射中的一個頁進行寫,
那么這種修改對于其他映射了相同文件的所有
進程來說都是可見的。
b.私有的:當進程創建的映射只是為讀文件,而不是寫文件時才會使用。處于這種目的,私有映射的效率要比共享映射的效率更高。
但是私有映射頁的認識寫操作都會使內核不再映射該文件中的頁。一個寫操作即不會改磁盤上的文件,
對訪問相同文件的其他進程來說這種改變也是不可見的。
c.使用mmap()系統調用創建一個新的內存映射。必須指定MAP_SHARED或MAP_PRIVATE標志。第九章、磁盤數據結構
1.任何Ext2分區中的第一個塊從不受Ext2文件系統的管理,因為這一塊是為啟動扇區所保留的。Ext2分區的其余部分被分成塊組(block group)。
2.塊組中的每個塊包含下列信息之一:
a.一個Ext2文件系統超級塊的拷貝
b.一組塊組描述符的拷貝
c.一個數據塊位圖:標識在一組中塊的使用和空閑狀況。
d.一個索引節點位圖
e.一組索引節點
f.屬于文件的一塊數據;即一個數據塊。
3.如果一個塊中不包含任何有意義的信息,就說這個塊是空的。
4.在Ext2文件系統中的所有塊組大小相同并被順序存放,因此,內核可以從塊組的整數索引很容易地得到磁盤中一個塊組的位置。
5.超級塊與組描述符被復制到每個塊組中。只有塊組0中所包含的超級塊和描述符才由內核使用,而其余的超級塊和組描述符保持不變
事實上,內核甚至不考慮它們。
6./sbin/e2fsck程序對Ext2文件系統的狀態執行一致性檢查時,就引用存放在塊組0中的超級塊和組描述符,然后把它們拷貝到其他所有的塊組中。
7.每組之多有8 x b塊,b是以字節單位的塊大小。
8.示例:
8GB的Ext2分區
塊的大小為4KB
塊位圖的大小4KB(b=4KB)
最多描述32KB的數據塊
每個塊組的容量:4KB x 32KB = 128MB
最多需要的塊組數: n = 8GB/128MB = 64
9.磁盤數據結構:
a.超級塊的域:
索引節點的總數
以塊位單位的文件系統的大小
保留的塊數
空閑塊計數器
空閑索引節點計數器
第一次使用的塊號(總為1)
塊的大小
片的大小
每組中的塊數
每組中的片數
.....
b.組描述符:每個塊組有自己的組描述符,為ext2_group_desc結構。
Ext2組描述符的域
塊位圖的塊號
索引節點位圖的塊號
第一個索引節點表塊的塊號
組中空閑塊的個數
組中索引節點的個數
組中目錄的個數
.....
c.位圖:是位的序列,0表示相應的索引節點塊或數據塊是空閑的,1表示占用。
d.索引節點表:所有索引節點的大小相同,即128字節。索引節點表第一個塊的塊號存放在組描述符的bg_inode_table域中。
Ext2磁盤索引節點的域:
文件類型和訪問權限
擁有者的標識符
以字節為單位的文件長度
最后一次文件訪問的時間
.......
文件的索引節點號沒有必要再磁盤上存放,因為它的值可以從塊組號和它在索引節點表中的相對于位置而得出。
10.Ext2的文件操作:
VFS方法的read和mmap是由很多文件系統共用的通用函數實現的。這些方法存放在
ext2_file_operations表中:
lseek -> ext2_file_lseek()
read -> generic_file_read()
write -> ext2_file_write()
.......
11.各種文件類型如何使用磁盤塊
正規文件:正規文件只有在開始有數據時才需要數據塊。
目錄:Ext2以一種特殊的文件實現了目錄,這種文件的數據塊存放了文件名和相應的所有節點號。
數據塊中包含了類型為ext2_dir_entry_2的結構
名字域最大為EXT2_NAME_LEN(通常是255)個字符的邊長數組。
目錄項的長度是4的倍數
符號鏈:符號鏈的路徑名達到60個字符,就把它存放在索引節點的i_blocks域,該域是由15個4字節整數組成的數組,因此無需數據塊
如果路徑名大于60個字符,就需要一個單獨的數據塊。
設備文件、管道和套接字:這些類型的文件不需要數據塊,所有必須的信息都存放在索引節點中。
12.Ext2文件的類型
0 未知
1 正規文件
2 目錄
3 字符設備
4 塊設備
5 命名管道
6 套接字
7 符號鏈
13.文件的洞是正規文件的一部分,它是一些空字符但沒有存放在磁盤的任何數據塊中。
引入文件的洞是為了避免磁盤空間的浪費。它們被廣泛地用在數據庫引用中,更一般的說,用于文件上散列法的所有應用。
第十八章 進程通信
1.進程間通信的機制:
管道和FIFO(管道):最適合在進程之間實現生產者/消費者的交互。有些進程往管道中寫入數據,而另外一些進程則從管道中讀取數據。
無名管道:用戶無法打開一個現有的管道。除非管道是由一個公共的祖先進程創建的。
有名管道:有磁盤索引節點,因此任何進程都可以訪問FIFO,沒有使用數據塊,使用內核緩沖區。
信號量IPC(Interprocess Communicatoin),表示一組系統調用,這組系統調用
允許用戶態進程:
a.通過信號量和其他進程進行同步
b.向其他進程發送消息或者從其他進程處接受消息
c.和其他進程共享一個線性區
使用IPC資源:
信號量:semget()
消息隊列:msgget()
共享內存:shmget()
消息:允許進程異步地交換信息(小塊數據)。可以認為消息是傳遞附加信息的信號。
共享內存:當進程之間在高效地共享大量數據時,這是一種最合適的交互方式。
套接字(socket):涉及到網絡相關。
第十章、程序的執行
1.進程概念:在Unix中是用來表示正在運行的一組程序競爭系統資源的行為。
2.內核需要處理的問題(把一組指令裝入內存并讓CPU執行):
不同的可執行文件格式: Linux的一個著名之處就是能執行其他操作系統所編譯的二進制文件。
共享庫: 很多可執行文件并不包含運行程序所需要的所有代碼,而是希望在運行時由內核從函數庫裝入函數。
執行上下文中的其他信息: 包括程序員熟悉的命令行參數與環境變量。
3.進程的信任狀和能力:Unix系統與每個進程的一些信任相關,信任狀把進程與一個特定的用戶或用戶組捆綁在一起。
信任狀在多用戶系統上尤為重要,因為信任狀可以決定每個進程能做什么,不能做什么,這樣既保證了每個用戶個人數據的完整性
也保證了系統整體上的穩定性。
a.進程的能力:一種能力僅僅是一個標志,它表明是否允許進程執行一個特定的操作或一組特定的操作。
4.庫:所有的全局外部符號名的線性地址。這些地址的分配或解析是由連接程序完成的,鏈接程序把程序所有的目標文件收集起來并構造可執行文件。
5.靜態庫/共享庫
動態庫的優缺點:進程不需要拷貝目標代碼、僅僅執行一個內存映射,把庫文件的相關部分映射到進程的地址空間中。
缺點也很明顯,動態的啟動時間較長,移植性也不如靜鏈接的好,系統中所包含的庫版本發生變化時,
動態庫連接的程序可能不適合本地運行。
靜態庫的優缺點:占用大量的磁盤空間。每個靜態連接的可執行文件都復制庫代碼的一部分。 gcc編譯器提供-static選項告訴鏈接程序使用靜態庫。
6.程序段和進程的線性區:
邏輯上,Unix程序的線性地址空間傳統上被劃分為幾個叫段(segment)的區間:
a.正文段:包含可執行代碼。
b.數據段:包含初始化的數據,也就是說,初始值存放在可執行文件中的所有靜態變量和全局變量(因為程序在啟動時必須知道它們的值)
c.bss段:包含未初始化的數據,也就是說,初值沒有存放在可執行文件中的所有全局變量(因為程序在引用它們之前才賦值)
d.堆棧段:包含程序的堆棧,堆棧中有返回地址、參數和被執行函數的局部變量。
堆:線性區包含動態分配給進程的內存區。
/sbin/init程序,它創建和監視在操作系統外層實現的所有進程的活動。init進程對應的線性區可以從(/proc/1/maps)文件得到這樣的信息。
7.執行跟蹤(execution tracing):是一個程序監視另一個程序執行的一種技術。被跟蹤的程序一步一步地執行,直到接受到一個信號或調用一個系統調用。
執行跟蹤由調試程序(debugger)廣泛應用,當然還使用其他技術(包括在被調試程序中插入斷點及運行時訪問它的變量)。
8.ptrace()系統調用進程執行跟蹤。設置了CAP_SYS_PTRACE能力的進程可以跟蹤系統中的任何進程(除了init)。
相反,沒有CAP_SYS_PTRACE能力的進程P只能跟蹤
與P有相同屬主的進程。此外,兩個進程不能同時跟蹤一個進程。
a.ptrace()系統調用修改被跟蹤進程描述符的p_pptr域以使它指向跟蹤進程,因此,跟蹤進程變為被跟蹤進程的有效父進程
跟蹤結束時,以PTRAC_DETACH命令調用ptrace()時,這個系統調用把p_pptr設置為p_oppter的值,恢復被跟蹤進程原來的父進程。
b.被跟蹤進程相關的幾個監控事件為:
一條單獨匯編指令執行的結束
進入一個系統調用
從一個系統調用退出
接收到一個信號
c.當一個監控的事件發生時,被跟蹤的程序停止,并將SIGCHID信號發送給它的父進程。當父進程希望恢復子進程的執行時,
就是用PTRACE_CONT、PTRACE_SINGLESTEP和
PTRACE_SYSCALL命令中的一條,這取決于父進程要監控那種事件。
9.可執行格式:Linux正式的可執行格式是ELF(Execuable and Linking Format)。
類型為linux_binfmt的對象所描述的可執行格式實質上提供以下三種方法:
a.loadbinary:通讀存放在可執行文件中的信息為當前進程建立一個新的執行環境。
b.load_shlib:用于動態地把一個共享庫捆綁到一個已經在運行的進程,這個是由uselib()系統調用激活的。
c.core_dump:在名為core的文件中存放當前進程的執行上下文。這個文件通常是在進程接收到一個缺省操作為"dump"的信號時被創建的
其格式取決于被執行程序的可執行類型。
linux_binfmt對象:處于一個簡單的連接鏈表中,第一個元素的地址被存放在formats變量中。
可以通過調用register_binfmt()和unregister_binfmt()函數
在鏈表中插入和刪除元素。
formats鏈表中的最后一個元素:是一個對解釋腳本(interpreted script)的可執行格式進行描述的一個對象。定義了load_binary()方法。
其相應的do_load_script()
可執行文件是否是以兩個#!開始,如果是,這個函數就以另一個可執行文件的路徑作為參數解釋第一行的其余部分,
并把文件名作為參數傳遞過去以執行這個腳本文件。
Linux允許用戶注冊自己定義的可執行格式:用如下的格式項/proc/sys/fs/binfmt_misc/register文件寫入一個字符串
:name:type:offset:string:mask:interpreter:
name:新格式的標識符
type:識別類型(M表示魔數,E表示擴展)
offse:魔數在文件中的起始偏移量
string:或者以魔數,或者以擴展名匹配的字節序列
mask:屏蔽string中的一些位的字符串
interpreter:程序解釋器的完整路徑名
可執行文件的前128字節填充linux_binprm結構的buf域。
exec類函數:這些函數能用可執行文件所描述的新上下文代替進程的上下文。
首先恭喜您,能夠認真的閱讀到這里,如果對部分理解不太明白,建議先將文章收藏起來,然后對不清楚的知識點進行查閱,然后在進行閱讀,相應你會有更深的認知。如果您喜歡這篇文章,就點個贊或者【關注我】吧!!
總結
以上是生活随笔為你收集整理的tipi 深入理解php内核 pdf_大牛的学习笔记-深入理解Linux内核(完整版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3000元电脑配置_2019年全新九代i
- 下一篇: python创建多个txt文件-pyth