Linux探用戶態與內核

1、 Unix/Linux的體系架構程序員

  如上圖所示,從宏觀上來看,Linux操做系統的體系架構分爲用戶態和內核態(或者用戶空間和內核)。內核從本質上看是一種軟件——控制計算機的硬件資源,並提供上層應用程序運行的環境。用戶態即上層應用程序的活動空間,應用程序的執行必須依託於內核提供的資源,包括CPU資源、存儲資源、I/O資源等。爲了使上層應用可以訪問到這些資源,內核必須爲上層應用提供訪問的接口:即系統調用。shell

  系統調用是操做系統的最小功能單位,這些系統調用根據不一樣的應用場景能夠進行擴展和裁剪,如今各類版本的Unix實現都提供了不一樣數量的系統調用,如Linux的不一樣版本提供了240-260個系統調用,FreeBSD大約提供了320個(reference:UNIX環境高級編程)。咱們能夠把系統調用當作是一種不能再化簡的操做(相似於原子操做,可是不一樣概念),有人把它比做一個漢字的一個「筆畫」,而一個「漢字」就表明一個上層應用,我以爲這個比喻很是貼切。所以,有時候若是要實現一個完整的漢字(給某個變量分配內存空間),就必須調用不少的系統調用。若是從實現者(程序員)的角度來看,這勢必會加劇程序員的負擔,良好的程序設計方法是:重視上層的業務邏輯操做,而儘量避免底層複雜的實現細節。庫函數正是爲了將程序員從複雜的細節中解脫出來而提出的一種有效方法。它實現對系統調用的封裝,將簡單的業務邏輯接口呈現給用戶,方便用戶調用,從這個角度上看,庫函數就像是組成漢字的「偏旁」。這樣的一種組成方式極大加強了程序設計的靈活性,對於簡單的操做,咱們能夠直接調用系統調用來訪問資源,如「人」,對於複雜操做,咱們藉助於庫函數來實現,如「仁」。顯然,這樣的庫函數依據不一樣的標準也能夠有不一樣的實現版本,如ISO C 標準庫,POSIX標準庫等。編程

  Shell是一個特殊的應用程序,俗稱命令行,本質上是一個命令解釋器,它下通系統調用,上通各類應用,一般充當着一種「膠水」的角色,來鏈接各個小功能程序,讓不一樣程序可以以一個清晰的接口協同工做,從而加強各個程序的功能。同時,Shell是可編程的,它能夠執行符合Shell語法的文本,這樣的文本稱爲Shell腳本,一般短短的幾行Shell腳本就能夠實現一個很是大的功能,緣由就是這些Shell語句一般都對系統調用作了一層封裝。爲了方便用戶和系統交互,通常,一個Shell對應一個終端,終端是一個硬件設備,呈現給用戶的是一個圖形化窗口。咱們能夠經過這個窗口輸入或者輸出文本。這個文本直接傳遞給shell進行分析解釋,而後執行。安全


總結一下,用戶態的應用程序能夠經過三種方式來訪問內核態的資源:網絡

1)系統調用架構

2)庫函數ide

3)Shell腳本函數

  下圖是對上圖的一個細分結構,從這個圖上能夠更進一步對內核所作的事有一個「全景式」的印象。主要表現爲:向下控制硬件資源,向內管理操做系統資源:包括進程的調度和管理、內存的管理、文件系統的管理、設備驅動程序的管理以及網絡資源的管理,向上則嚮應用程序提供系統調用的接口。從總體上來看,整個操做系統分爲兩層:用戶態和內核態,這種分層的架構極大地提升了資源管理的可擴展性和靈活性,並且方便用戶對資源的調用和集中式的管理,帶來必定的安全性。性能

2、用戶態和內核態的切換spa

  由於操做系統的資源是有限的,若是訪問資源的操做過多,必然會消耗過多的資源,並且若是不對這些操做加以區分,極可能形成資源訪問的衝突。因此,爲了減小有限資源的訪問和使用衝突,Unix/Linux的設計哲學之一就是:對不一樣的操做賦予不一樣的執行等級,就是所謂特權的概念。簡單說就是有多大能力作多大的事,與系統相關的一些特別關鍵的操做必須由最高特權的程序來完成。Intel的X86架構的CPU提供了0到3四個特權級,數字越小,特權越高,Linux操做系統中主要採用了0和3兩個特權級,分別對應的就是內核態和用戶態。運行於用戶態的進程能夠執行的操做和訪問的資源都會受到極大的限制,而運行在內核態的進程則能夠執行任何操做而且在資源的使用上沒有限制。不少程序開始時運行於用戶態,但在執行的過程當中,一些操做須要在內核權限下才能執行,這就涉及到一個從用戶態切換到內核態的過程。好比C函數庫中的內存分配函數malloc(),它具體是使用sbrk()系統調用來分配內存,當malloc調用sbrk()的時候就涉及一次從用戶態到內核態的切換,相似的函數還有printf(),調用的是wirte()系統調用來輸出字符串,等等。

  到底在什麼狀況下會發生從用戶態到內核態的切換,通常存在如下三種狀況:

1)固然就是系統調用:緣由如上的分析。

2)異常事件: 當CPU正在執行運行在用戶態的程序時,忽然發生某些預先不可知的異常事件,這個時候就會觸發從當前用戶態執行的進程轉向內核態執行相關的異常事件,典型的如缺頁異常。

3)外圍設備的中斷:當外圍設備完成用戶的請求操做後,會像CPU發出中斷信號,此時,CPU就會暫停執行下一條即將要執行的指令,轉而去執行中斷信號對應的處理程序,若是先前執行的指令是在用戶態下,則天然就發生從用戶態到內核態的轉換。

  注意:系統調用的本質其實也是中斷,相對於外圍設備的硬中斷,這種中斷稱爲軟中斷,這是操做系統爲用戶特別開放的一種中斷,如Linux int 80h中斷。因此,從觸發方式和效果上來看,這三種切換方式是徹底同樣的,都至關因而執行了一箇中斷響應的過程。可是從觸發的對象來看,系統調用是進程主動請求切換的,而異常和硬中斷則是被動的。

3、總結

  本文僅是從宏觀的角度去理解Linux用戶態和內核態的設計,並無去深究它們的具體實現方式。從實現上來看,必需要考慮到的一點我想就是性能問題,由於用戶態和內核態之間的切換也會消耗大量資源。關於實現的細節,目前學藝不精不敢亂說,等往後補上。但知道了這一點,我相信對不少問題也就很容易理解了,好比說基於緩衝區的IO和無緩衝的IO,用戶進程和內核進程之間的切換,IO複用中的讀寫內核事件表,等等,這些知識以後會一一補上。

相關文章
相關標籤/搜索