神奇知識:鍵盤敲入 A 字母時,操做系統在這期間發生了什麼…

前言

鍵盤能夠說是咱們最常使用的輸入硬件設備了,但身爲程序員的你,你知道「鍵盤敲入 A 字母時,操做系統期間發生了什麼嗎」?程序員

那要想知道這個發生的過程,咱們得先了解了解「操做系統是如何管理多種多樣的的輸入輸出設備」的,等了解完這個後,咱們再來看看這個問題,你就會發現問題已經被迎刃而解了。算法

 

設備控制器數據庫

咱們的電腦設備能夠接很是多的輸入輸出設備,好比鍵盤、鼠標、顯示器、網卡、硬盤、打印機、音響等等,每一個設備的用法和功能都不一樣,那操做系統是如何把這些輸入輸出設備統一管理的呢?編程

爲了屏蔽設備之間的差別,每一個設備都有一個叫設備控制器(Device Control) 的組件,好比硬盤有硬盤控制器、顯示器有視頻控制器等。緩存

 

計算機 I/O 系統結構

由於這些控制器都很清楚的知道對應設備的用法和功能,因此 CPU 是經過設備控制器來和設備打交道的。微信

設備控制器裏有芯片,它可執行本身的邏輯,也有本身的寄存器,用來與 CPU 進行通訊,好比:架構

經過寫入這些寄存器,操做系統能夠命令設備發送數據、接收數據、開啓或關閉,或者執行某些其餘操做。框架

經過讀取這些寄存器,操做系統能夠了解設備的狀態,是否準備好接收一個新的命令等。函數

實際上,控制器是有三類寄存器,它們分別是狀態寄存器(Status Register)、 命令寄存器(Command Register)以及數據寄存器(Data Register),以下圖:學習

 

這三個寄存器的做用:

數據寄存器,CPU 向 I/O 設備寫入須要傳輸的數據,好比要打印的內容是「Hello」,CPU 就要先發送一個 H 字符給到對應的 I/O 設備。

命令寄存器,CPU 發送一個命令,告訴 I/O 設備,要進行輸入/輸出操做,因而就會交給 I/O 設備去工做,任務完成後,會把狀態寄存器裏面的狀態標記爲完成。

狀態寄存器,目的是告訴 CPU ,如今已經在工做或工做已經完成,若是已經在工做狀態,CPU 再發送數據或者命令過來,都是沒有用的,直到前面的工做已經完成,狀態寄存標記成已完成,CPU 才能發送下一個字符和命令。

CPU 經過讀、寫設備控制器中的寄存器來控制設備,這可比 CPU 直接控制輸入輸出設備,要方便和標準不少。

另外, 輸入輸出設備可分爲兩大類 :塊設備(Block Device)字符設備(Character Device)

塊設備,把數據存儲在固定大小的塊中,每一個塊有本身的地址,硬盤、USB 是常見的塊設備。

字符設備,以字符爲單位發送或接收一個字符流,字符設備是不可尋址的,也沒有任何尋道操做,鼠標是常見的字符設備。

塊設備一般傳輸的數據量會很是大,因而控制器設立了一個可讀寫的數據緩衝區

CPU 寫入數據到控制器的緩衝區時,當緩衝區的數據囤夠了一部分,纔會發給設備。

CPU 從控制器的緩衝區讀取數據時,也須要緩衝區囤夠了一部分,才拷貝到內存。

這樣作是爲了,減小對設備的操做次數。

那 CPU 是如何與設備的控制寄存器和數據緩衝區進行通訊的?存在兩個方法:

端口 I/O,每一個控制寄存器被分配一個 I/O 端口,能夠經過特殊的彙編指令操做這些寄存器,好比 in/out 相似的指令。

內存映射 I/O,將全部控制寄存器映射到內存空間中,這樣就能夠像讀寫內存同樣讀寫數據緩衝區。

I/O 控制方式

在前面我知道,每種設備都有一個設備控制器,控制器至關於一個小 CPU,它能夠本身處理一些事情,但有個問題是,當 CPU 給設備發送了一個指令,讓設備控制器去讀設備的數據,它讀完的時候,要怎麼通知 CPU 呢?

控制器的寄存器通常會有狀態標記位,用來標識輸入或輸出操做是否完成。因而,咱們想到第一種輪詢等待的方法,讓 CPU 一直查寄存器的狀態,直到狀態標記爲完成,很明顯,這種方式很是的傻瓜,它會佔用 CPU 的所有時間。

那咱們就想到第二種方法 —— 中斷,通知操做系統數據已經準備好了。咱們通常會有一個硬件的中斷控制器,當設備完成任務後觸發中斷到中斷控制器,中斷控制器就通知 CPU,一箇中斷產生了,CPU 須要停下當前手裏的事情來處理中斷。

另外,中斷有兩種,一種軟中斷,例如代碼調用 INT 指令觸發,一種是硬件中斷,就是硬件經過中斷控制器觸發的。

但中斷的方式對於頻繁讀寫數據的磁盤,並不友好,這樣 CPU 容易常常被打斷,會佔用 CPU 大量的時間。對於這一類設備的問題的解決方法是使用 DMA(Direct Memory Access) 功能,它可使得設備在 CPU 不參與的狀況下,可以自行完成把設備 I/O 數據放入到內存。那要實現 DMA 功能要有 「DMA 控制器」硬件的支持。

 

DMA 的工做方式以下:

CPU 需對 DMA 控制器下發指令,告訴它想讀取多少數據,讀完的數據放在內存的某個地方就能夠了;

接下來,DMA 控制器會向磁盤控制器發出指令,通知它從磁盤讀數據到其內部的緩衝區中,接着磁盤控制器將緩衝區的數據傳輸到內存;

當磁盤控制器把數據傳輸到內存的操做完成後,磁盤控制器在總線上發出一個確認成功的信號到 DMA 控制器;

DMA 控制器收到信號後,DMA 控制器發中斷通知 CPU 指令完成,CPU 就能夠直接用內存裏面現成的數據了;

能夠看到, CPU 當要讀取磁盤數據的時候,只需給 DMA 控制器發送指令,而後返回去作其餘事情,當磁盤數據拷貝到內存後,DMA 控制機器經過中斷的方式,告訴 CPU 數據已經準備好了,能夠從內存讀數據了。僅僅在傳送開始和結束時須要 CPU 干預。

設備驅動程序

雖然設備控制器屏蔽了設備的衆多細節,但每種設備的控制器的寄存器、緩衝區等使用模式都是不一樣的,因此爲了屏蔽「設備控制器」的差別,引入了設備驅動程序

 

設備控制器不屬於操做系統範疇,它是屬於硬件,而設備驅動程序屬於操做系統的一部分,操做系統的內核代碼能夠像本地調用代碼同樣使用設備驅動程序的接口,而設備驅動程序是面向設備控制器的代碼,它發出操控設備控制器的指令後,才能夠操做設備控制器。

不一樣的設備控制器雖然功能不一樣,可是設備驅動程序會提供統一的接口給操做系統,這樣不一樣的設備驅動程序,就能夠以相同的方式接入操做系統。以下圖:

 

前面提到了很多關於中斷的事情,設備完成了事情,則會發送中斷來通知操做系統。那操做系統就須要有一個地方來處理這個中斷,這個地方也就是在設備驅動程序裏,它會及時響應控制器發來的中斷請求,並根據這個中斷的類型調用響應的中斷處理程序進行處理。

一般,設備驅動程序初始化的時候,要先註冊一個該設備的中斷處理函數。

 

咱們來看看,中斷處理程序的處理流程:

在 I/O 時,設備控制器若是已經準備好數據,則會經過中斷控制器向 CPU 發送中斷請求;

保護被中斷進程的 CPU 上下文;

轉入相應的設備中斷處理函數;

進行中斷處理;

恢復被中斷進程的上下文;

通用塊層

對於塊設備,爲了減小不一樣塊設備的差別帶來的影響,Linux 經過一個統一的通用塊層,來管理不一樣的塊設備。

通用塊層是處於文件系統和磁盤驅動中間的一個塊設備抽象層,它主要有兩個功能:

第一個功能,向上爲文件系統和應用程序,提供訪問塊設備的標準接口,向下把各類不一樣的磁盤設備抽象爲統一的塊設備,並在內核層面,提供一個框架來管理這些設備的驅動程序;

第二功能,通用層還會給文件系統和應用程序發來的 I/O 請求排隊,接着會對隊列從新排序、請求合併等方式,也就是 I/O 調度,主要目的是爲了提升磁盤讀寫的效率。

Linux 內存支持 5 種 I/O 調度算法,分別是:

(1)沒有調度算法

(2)先入先出調度算法

(3)徹底公平調度算法

(4)優先級調度

(5)最終期限調度算法

第一種,沒有調度算法,是的,你沒聽錯,它不對文件系統和應用程序的 I/O 作任何處理,這種算法經常使用在虛擬機 I/O 中,此時磁盤 I/O 調度算法交由物理機系統負責。

第二種,先入先出調度算法,這是最簡單的 I/O 調度算法,先進入 I/O 調度隊列的 I/O 請求先發生。

第三種,徹底公平調度算法,大部分系統都把這個算法做爲默認的 I/O 調度器,它爲每一個進程維護了一個 I/O 調度隊列,並按照時間片來均勻分佈每一個進程的 I/O 請求。

第四種,優先級調度算法,顧名思義,優先級高的 I/O 請求先發生, 它適用於運行大量進程的系統,像是桌面環境、多媒體應用等。

第五種,最終期限調度算法,分別爲讀、寫請求建立了不一樣的 I/O 隊列,這樣能夠提升機械磁盤的吞吐量,並確保達到最終期限的請求被優先處理,適用於在 I/O 壓力比較大的場景,好比數據庫等。

存儲系統 I/O 軟件分層

前面說到了很多東西,設備、設備控制器、驅動程序、通用塊層,如今再結合文件系統原理,咱們來看看 Linux 存儲系統的 I/O 軟件分層。

能夠把 Linux 存儲系統的 I/O 由上到下能夠分爲三個層次,分別是文件系統層、通用塊層、設備層。他們整個的層次關係以下圖:

 

這三個層次的做用是:

文件系統層,包括虛擬文件系統和其餘文件系統的具體實現,它向上爲應用程序統一提供了標準的文件訪問接口,向下會經過通用塊層來存儲和管理磁盤數據。

通用塊層,包括塊設備的 I/O 隊列和 I/O 調度器,它會對文件系統的 I/O 請求進行排隊,再經過 I/O 調度器,選擇一個 I/O 發給下一層的設備層。

設備層,包括硬件設備、設備控制器和驅動程序,負責最終物理設備的 I/O 操做。

有了文件系統接口以後,不但能夠經過文件系統的命令行操做設備,也能夠經過應用程序,調用 read、write 函數,就像讀寫文件同樣操做設備,因此說設備在 Linux 下,也只是一個特殊的文件。

可是,除了讀寫操做,還須要有檢查特定於設備的功能和屬性。因而,須要 ioctl 接口,它表示輸入輸出控制接口,是用於配置和修改特定設備屬性的通用接口。

另外,存儲系統的 I/O 是整個系統最慢的一個環節,因此 Linux 提供了很多緩存機制來提升 I/O 的效率。

爲了提升文件訪問的效率,會使用頁緩存、索引節點緩存、目錄項緩存等多種緩存機制,目的是爲了減小對塊設備的直接調用。

爲了提升塊設備的訪問效率, 會使用緩衝區,來緩存塊設備的數據。

鍵盤敲入字母時,期間發生了什麼?

看完前面的內容,相信你對輸入輸出設備的管理有了必定的認識,那接下來就從操做系統的角度回答開頭的問題「鍵盤敲入字母時,操做系統期間發生了什麼?」

咱們先來看看 CPU 的硬件架構圖:

 

CPU 裏面的內存接口,直接和系統總線通訊,而後系統總線再接入一個 I/O 橋接器,這個 I/O 橋接器,另外一邊接入了內存總線,使得 CPU 和內存通訊。再另外一邊,又接入了一個 I/O 總線,用來鏈接 I/O 設備,好比鍵盤、顯示器等。

那當用戶輸入了鍵盤字符,鍵盤控制器就會產生掃描碼數據,並將其緩衝在鍵盤控制器的寄存器中,緊接着鍵盤控制器經過總線給 CPU 發送中斷請求

CPU 收到中斷請求後,操做系統會保存被中斷進程的 CPU 上下文,而後調用鍵盤的中斷處理程序

鍵盤的中斷處理程序是在鍵盤驅動程序初始化時註冊的,那鍵盤中斷處理函數的功能就是從鍵盤控制器的寄存器的緩衝區讀取掃描碼,再根據掃描碼找到用戶在鍵盤輸入的字符,若是輸入的字符是顯示字符,那就會把掃描碼翻譯成對應顯示字符的  ASCII 碼,好比用戶在鍵盤輸入的是字母 A,是顯示字符,因而就會把掃描碼翻譯成 A 字符的 ASCII 碼。

獲得了顯示字符的 ASCII 碼後,就會把 ASCII 碼放到「讀緩衝區隊列」,接下來就是要把顯示字符顯示屏幕了,顯示設備的驅動程序會定時從「讀緩衝區隊列」讀取數據放到「寫緩衝區隊列」,最後把「寫緩衝區隊列」的數據一個一個寫入到顯示設備的控制器的寄存器中的數據緩衝區,最後將這些數據顯示在屏幕裏。

顯示出結果後,恢復被中斷進程的上下文

以上就是本篇文章的所有內容,但願對你們有幫助哦~

另外筆者仍是一名CC++的程序員,若是你想更好的提高你的編程能力,好好學習C/C++編程知識的話!那麼你很幸運~

C語言C++編程學習交流圈子,Q羣1090842465點擊進入】微信公衆號:C語言編程學習基地

分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)

歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比本身琢磨更快哦!

編程學習書籍:

編程學習視頻:

相關文章
相關標籤/搜索