1. 程式人生 > >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子系統提供了統一裝置訪問介面,就像系統呼叫為應用程式與作業系統之間提供了統一地標準介面一樣。

I/O硬體

    計算機使用很多種裝置。絕大多數都屬於儲存裝置(磁碟,磁帶)、傳輸裝置(網絡卡、Modem)和人機互動裝置(螢幕,鍵盤,滑鼠)。

    裝置與計算系統的通訊可以通過電纜甚至空氣來傳送資訊。裝置與計算機通訊通過一個連線點(或),例如串列埠。如果一個或多個裝置使用一組共同的線,那麼這種連線則成為匯流排。匯流排(Bus)是一組線和一組嚴格定義的可以描述在線上傳輸資訊的協議。

    匯流排在計算機系統結構中使用很廣。下圖顯示了一個典型的PC匯流排結構。該圖顯示了一個PCI匯流排

(最為常用的PC系統匯流排)用以連線處理器-記憶體子系統與快速裝置,擴充套件匯流排(expansion bus)用於連線序列、並行埠和相對較慢的裝置(如磁碟)。

    控制器(controller)是用於操作埠,匯流排或裝置的一組電子電器。串列埠控制器是簡單的裝置控制器。它是計算機上的一塊晶片或部分晶片,用以控制串列埠線上的訊號。相比較而言,SCSI匯流排就不那麼簡單。由於SCSI協議的複雜性,SCSI匯流排控制器常常實現為與計算機相連的獨立的線路板或主機介面卡(host adapter)。該介面卡通常有處理器、微碼及一部分私有記憶體,以便能處理SCSI協議資訊。有的裝置有內建的控制器。控制器有一個或多個用於資料和控制訊號的暫存器。處理器通過讀寫這些暫存器的位模式來與控制器通訊。這種通訊的一種方法是通過使用特殊I/O指令來向指定的I/O埠地址傳輸一個位元組或字。I/O指令觸發匯流排線路來選擇合適裝置並將資訊傳入或傳出裝置暫存器。另外,裝置控制器也可支援記憶體對映I/O。

這時,裝置控制暫存器被對映到處理器的地址空間。處理器執行I/O請求是通過標準資料傳輸指令來完成對裝置控制器的讀寫。

    有的系統使用兩種技術。例如,PC使用I/O指令來控制一些裝置,而使用記憶體對映來控制其他裝置。下圖顯示了常用的PC I/O埠地址。

影象控制器不但有I/O埠以完成基本控制操作,而且也有一個較大的記憶體對映區域以支援螢幕內容。程序通過將資料寫入到記憶體對映區域來把輸出傳送到螢幕。影象控制器可以根據記憶體中的內容來生成螢幕影象。這種技術使用簡單,而且向影象記憶體中寫入數百萬位元組要比執行數百萬條指令快很多。但是向記憶體對映I/O控制器寫入的簡單性也存在一個缺點。因為軟體出錯的常見型別之一就是通過一個錯誤指標向一個不該寫的記憶體區域寫資料,所以記憶體對映裝置暫存器容易受到意外修改。當然,記憶體保護可以減低風險。

    I/O埠通常有4中暫存器,即狀態暫存器,控制暫存器,資料輸入暫存器與資料輸出暫存器。

    資料輸入暫存器被主機讀出以獲取資料。

    資料輸出暫存器被主機寫入以傳送資料。

    狀態暫存器包含一些主機可讀取的位(bit)。這些位指示各種狀態,例如,當前任務是否完成,資料輸入暫存器中是否有資料可以讀取,是否出現裝置故障等。

    控制暫存器可以被主機用來向裝置傳送命令或改變裝置狀態。例如,一個串列埠的控制暫存器中的一個確定的位選擇全功通訊或單工通訊,另一個位控制啟動奇偶校驗檢查,第三個位設定字長位7或8位,其他位選擇串列埠通訊所支援的速度。

    資料暫存器通常為1-4B。有的控制器有FIFO晶片,可用來保留多個輸入或輸出資料,以在資料暫存器大小的基礎上擴充套件控制器的容量。FIFO晶片可以保留少量突發資料,直到裝置或主機可以接受資料。

輪詢

    主機與控制器之間互動的完成協議可能很複雜,但基本握手概念則比較簡單。下面舉例解釋握手概念。假設有兩個位來協調控制器與主機之間的生產者與消費者的關係。控制器通過狀態暫存器的忙位(busy bit)來顯示其狀態(記住置位(set a bit)就是將1寫到位中,而清位(clear a bit)就是將0寫到位中)。控制器工作忙時就置忙位,而可以接受下一命令時就清忙位。主機通過命令暫存器中命令就緒位來表示其意願。當主機有命令需要控制器執行時,就置命令就緒位。例如,當主機需要通過埠來寫輸出資料時,主機與控制器之間握手協調如下:

  1. 主機不斷地讀取忙位,直到該位被清除。
  2. 主機裝置命令暫存器中的寫位並向資料輸出暫存器中寫入一個位元組。
  3. 主機裝置命令就緒位。
  4. 當控制器注意到命令就緒位已被設定,則設定忙位。    
  5. 控制器讀取命令暫存器,並看到寫命令。它從資料輸出暫存器中讀取一個位元組,並向裝置執行I/O操作。
  6. 控制器清除命令就緒位,清除狀態暫存器的故障位表示裝置I/O成功,清除忙位表示完成。

    輸出每個位元組,都要執行以上迴圈。可以看出效率比較低。

    這時,如果讓裝置準備好時再通知處理器而不是由CPU輪詢外設I/O是否已完成,那麼效率就會更好。能使外設通知CPU的硬體機制稱為中斷(interrupt)。

中斷

    基本中斷機制工作如下。CPU硬體有一條中斷請求線(Interrupt-request line, IRL)。CPU在執行完每條指令後,都將檢測IRL。當CPU檢測到已經有控制器通過中斷請求線傳送了訊號,CPU將儲存當前狀態並且跳轉到記憶體固定位置的中斷處理程式(interrupt-controller)。中斷處理程式判斷中斷原因,進行必要的處理,重新恢復狀態,最後執行中斷返回(return from interrupt)指令以便使CPU返回中斷以前的執行狀態,即裝置控制器通過中斷請求線傳送訊號而引起(raise)中斷,CPU捕獲(catch)中斷並分發(dispatch)到中斷處理程式中,中斷處理程式通過處理裝置請求來清除(clear)中斷。下圖總結中斷驅動I/O迴圈。

    這一基本中斷機制可以使CPU響應非同步事件,例如,裝置控制器處於就緒狀態,對於現代作業系統,需要更為成熟的中斷處理特性,在進行關鍵處理時,能夠延遲中斷處理。更為有效將中斷分發到合適的中斷處理程式,而不是檢查所有裝置以決定哪個裝置引起中斷。需要多級中斷,這樣作業系統能區分高優先順序或低優先順序的中斷,能根據緊迫性的程式來響應。

    對於現代計算機硬體來說,這三個特性是由CPU與中斷控制器(interrupt-controller)硬體提供的。

    絕大多數CPU有兩個中斷請求線。一個是非遮蔽中斷,主要用來處理如不可恢復記憶體錯誤等時間。另一個是可遮蔽中斷,這可以由CPU在執行關鍵的不可中斷的指令序列前加以遮蔽。可遮蔽中斷可以被裝置控制器用來請求服務。

    中斷機制接受一個地址,以用來從一小集合內選擇特定的中斷處理程式。對絕大多數體系機構,這個地址是一個稱為中斷向量(interrupt vector)的表中偏移量。該向量包含了特殊中斷處理程式的記憶體地址。向量中斷機制的目的是用減少單箇中斷處理的需要,這些中斷處理搜尋所有可能的中斷源以決定哪個中斷需要服務。事實上,計算機裝置常常要比向量內的地址多。解決這一問題的常用方法之一就是中斷連結(interupt chaning)技術,即中斷向量內的每個元素都指向中斷處理程式列表的頭。當有中斷髮生時,相應連結串列上的所有中斷處理程式都將一一呼叫,直到發現可以處理請求的為止。這種結構是大型中斷向量表的大開銷與分發到單箇中斷處理程式的低效率之間的一個折中。

    下圖顯示了Intel Pentium中斷向量的設計。事件0-31為非遮蔽中斷,用來表示各種錯誤條件訊號。事件32-255位為可遮蔽中斷,用於裝置產生的中斷。

    中斷機制也實現了中斷優先順序(interrupt priority)。該中斷機制能使CPU延遲處理低優先順序中斷而不遮蔽所有中斷,也可以讓高優先順序中斷搶佔低優先順序中斷處理。

      

 

 

 

    現代作業系統可以與中斷機制進行多種方式的互動。在啟動時,作業系統探查硬體匯流排以發現哪些裝置是存在的,而且將相應中斷處理程式安裝到中斷向量中。在I/O過程中,各種裝置控制器如果準備好服務就會觸發中斷。這些中斷表示輸出已完成,或輸入資料已準備好,或已檢測到錯誤。中斷機制也用來處理各種異常,如被0除,訪問一個受保護的或不存在的記憶體地址,企圖從使用者態執行一個特權指令。觸發中斷的事件有一個共同特點:它們都是會導致CPU去執行一個緊迫的自我獨立的程式的事件。

    對於能夠儲存少量處理器的狀態並能呼叫核心中的特權程式的高效硬體和軟體機制來說,作業系統還有其他用途。例如,許多作業系統使用中斷機制進行虛擬記憶體分頁。頁錯誤引起中斷異常,該中斷會掛起當前程序並跳轉到核心的頁錯誤處理程式。該處理程式儲存程序狀態,將所中斷地程序加到等待佇列中,進行頁面快取管理,安排一個I/O操作來獲取所需頁面,安排另一個程序恢復執行,並從中斷返回。

    另一個例子是系統呼叫的實現。通常一個程式使用庫呼叫來執行系統呼叫。庫程式檢查應用程式所給的引數,建立一個數據結構將引數傳遞給核心,並執行一個稱為軟中斷(software interrupt)或者陷阱指令(trap)的特殊指令。該指令有一個引數用來標識所需的核心服務。當系統呼叫執行陷阱指令時,中斷硬體會儲存使用者程式碼的狀態,切換到核心模式,分派到實現所請求服務的核心程式。陷阱所賦予的中斷優先順序要比裝置中斷優先順序要低----位應用程式執行系統呼叫與在FIFO佇列溢位並丟去資料之前的處理裝置控制器相比,後者更為緊迫。

    多執行緒的核心體系結構非常適合實現多優先順序中斷,並確保中斷處理的優先順序要高於核心後臺處理和使用者程式的優先順序。

    總而言之,中斷在現代作業系統中用來處理非同步事件和設定陷阱進入核心模式的管理程式。為了能使最緊迫的工作先做,現代計算機都使用中斷優先順序。裝置控制器,硬體錯誤,系統呼叫都可以引起中斷並觸發核心程式。由於中斷大量地用於時間敏感的處理,所以高效能系統需要高效中斷處理。

直接記憶體訪問

    對於需要做大量傳輸的裝置,例如磁碟驅動器,如果使用昂貴的通用處理器來觀察狀態位並按位元組來向控制器暫存器送入資料---------一個稱為程式控制I/O(Programmed I/O,PIO)的過程,那麼就浪費了。許多計算機位為了避免用PIO增加CPU的負擔,將一部分任務放給一個專用處理器,稱之為直接記憶體訪問(direct-memory access, DMA)控制器。在開始DMA傳輸時,主機向記憶體寫入DMA命令塊。該塊包括傳輸的源地址指標,傳輸的目的地指標,傳輸的位元組數。CPU在將該命令塊的地址寫入到DMA控制器中後,就繼續其他工作。DMA控制器則繼續下去直接操作記憶體匯流排,無須主CPU的幫助,就可以將地址放到匯流排以開始傳輸。一個簡單的DMA控制器已經是PC的標準部件。一般來說,PC上採用匯流排控制I/O的主機板都擁有它們自己的高速DMA硬體。

    DMA控制器與裝置控制器之間的握手通過一對稱為DMA-request和DMA-acknowledge的線來進行。當有資料需要傳輸時,裝置控制器就通過DMA-request線傳送訊號。該訊號會導致DMA控制器抓住記憶體匯流排,並在記憶體地址總線上放上所需地址,並通過DMA-acknowledge線傳送訊號。當裝置控制器收到DMA-acknowlege訊號時,就可以向記憶體傳輸資料,並清除DMA-request請求訊號。

    當整個傳輸完成後,DMA控制器中斷CPU。下圖描述了這一過程。

    當DMA控制器抓住記憶體匯流排時,CPU會暫時不能訪問主記憶體,但可以訪問一級或二級快取記憶體中的資料項。雖然這種週期挪用(cycle stealing)可能放慢CPU計算,但是將資料傳輸工作交給DMA控制器常常能改善系統總體效能。有的計算機體系結構的DMA使用實體記憶體地址,而有的使用直接虛擬記憶體訪問(direct virtual-memory access DVMA),這裡所使用的虛擬記憶體地址需要經過虛擬到實體地址裝換。DVMA可以直接實現兩個記憶體對映裝置之間的傳輸,而無需CPU的干涉或使用主記憶體。

    對於保護模式核心,作業系統通常不允許程序直接向裝置傳送命令。該規定保護資料以免違反訪問控制,並保護系統不因裝置控制器的錯誤使用而崩潰。取而代之的是,作業系統匯出一些函式,這些函式可以被具有足夠特權的程序來訪問低層硬體的低層操作。對於沒有沒有核心保護的核心,程序可以直接訪問裝置控制器。該直接訪問可以得到高效能,這是因為它避免了核心通訊,上下文切換及核心軟體層。不過,這也破壞了系統的安全與穩定。通用作業系統的發展趨勢是保護記憶體和裝置,這樣系統可以預防錯誤或惡意應用程式的破壞。

I/O應用介面

    下圖說明了核心中與I/O相關部分是如何按軟體層來組織的。

裝置驅動程式層的作用是為核心I/O子系統隱藏裝置控制器之間的差異,就如同I/O系統呼叫通用型別封裝了裝置行行為,為應用程式隱藏了硬體差異。將I/O子系統與硬體分離簡化了作業系統開發人員的任務。

    絕大多數作業系統存在後門(escape或back door),這允許應用程式將任務命令透明地址傳遞到裝置控制器。

塊與字元裝置

    塊裝置介面規定了訪問磁碟驅動器和其他基於塊裝置所需的各個方面。通常裝置應能理解read()和write()命令,如果是隨機訪問裝置,也應有seek()命令以描述下次傳輸哪個塊。應用程式通常通過檔案系統介面訪問裝置。大家看到read(),write(),see()描述了塊儲存裝置的基本特點,這樣應用程式就不必關注這些裝置的低層差別。

    作業系統本身和特殊應用程式(如資料庫管理系統)可能更加傾向於將塊裝置當做一個簡單的線性陣列來訪問。這種訪問方式有時稱為原始I/O。如果應用程式執行自己的緩衝,那麼使用檔案系統會引起額外的不必要的緩衝。同樣的,如果應用程式提供自己的檔案塊或者域的加鎖,那麼作業系統服務就會閒的多餘,在最壞的情況下甚至帶來衝突。為了避免這些衝突,將原始裝置訪問控制由作業系統直接轉移到應用程式。這樣的後果是管理裝置的作業系統服務不再存在了。一種越來越常見的折中辦法是允許禁止快取和鎖的檔案操作模式。在UNIX中,這種方式稱為直接I/O(direct I/O)。

    記憶體對映檔案訪問時建立在塊裝置驅動程式之上的。記憶體對映介面並不提供read和write操作,而是通過記憶體中的位元組陣列來訪問磁碟儲存。將檔案對映到記憶體的系統呼叫返回一個位元組陣列的虛擬記憶體地址,該位元組組數包含了檔案的一個副本。實際的資料傳輸在需要時才執行,以滿足記憶體映像的訪問。因為傳輸採用了與按需分頁虛擬記憶體訪問相同的機制,所以記憶體對映I/O比較高效。記憶體對映也有益於程式設計師-----訪問記憶體對映檔案像讀寫記憶體一樣簡單。提供虛擬記憶體的作業系統常常為記憶體服務提供對映介面。例如,為執行程式,作業系統將可執行程式對映到記憶體中,並切換到可執行程式的入口地址。記憶體對映也常被核心用來訪問磁碟交換空間。

    鍵盤是一種可以通過位元組流介面訪問的裝置。這類介面的基本系統呼叫使得應用程式可以get()或put()一個字元。在此介面之上,可以構造庫以提供具有緩衝和編輯功能的按行訪問。

網路裝置

    由於網路I/O的效能和訪問特點與磁碟I/O相比有很大差別,絕大多數作業系統所提供的網路I/O介面也不同於磁碟的read()-write()-seek()介面。許多作業系統所提供的介面是網路Socket介面,如UNIX和Windows NT。

    想一下牆上的電源插座:任何電器都可以插入。同樣,Socket介面的系統呼叫可以讓應用程式建立一個Socket,連線本地Socket和遠端地址(將本地應用程式與由遠端應用程式建立的Socket相連),監聽要與本地Socket相連的遠端應用程式,通過連線傳送和接收資料。為了支援伺服器的實現,Socket介面還提供了select()函式,以管理一組Sockt。

時鐘與定時器

    許多計算機都有硬體時鐘和定時器以提供如下三個基本函式:

  • 獲取當前時間
  • 獲取已經逝去的時間
  • 設定訂時器,以在T時觸發操作X

這些函式被作業系統和時間敏感的應用程式大量使用。不過,實現這些函式的系統呼叫並沒有在作業系統之間實現標準化。

    測量逝去時間和觸發操作的硬體稱為可程式設計間隔定時器(programmable interval timer)。它可被設定為等待一定的時間,然後觸發中斷。它也可以設定成做一次或重複多次,以產生週期性中斷。排程程式可以使用這種機制來產生中斷,以搶佔時間片用完的程序。

    對許多計算機,由硬體時鐘產生的中斷率約在每秒18-60次計時單元(tick)。

阻塞與非阻塞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請求。為此,作業系統為裝置狀態表(device status table)配備等待佇列。核心管理這個表,表中包含了每一個I/O裝置的條目,每個表條目表明了裝置型別、地址和狀態(不工作,空閒或忙)。如果裝置在忙於一個請求,那麼請求的型別和其他引數將會被儲存在該裝置的表條目中。

    I/O子系統改善計算機效率的一種方法是進行I/O操作排程。另一種方法是使用主存貨磁碟上的儲存空間的技術,如緩衝,高速緩衝,假離線。

緩衝

    緩衝區是用來儲存兩個裝置之間或在裝置和應用程式之間所傳輸資料的記憶體區域。

快取記憶體

    快取記憶體(cache)是可以保留資料副本的高速儲存器。高速緩衝區副本的訪問要比原始資料訪問要更為高效。緩衝與快取記憶體的差別是緩衝可能是資料項的唯一副本,而根據定義快取記憶體只是提供了一個駐留在其他地方的資料在高速儲存上的一個副本。

假離線與裝置預留

    假離線(Spooling)是用來儲存裝置輸出的緩衝區,這些裝置(如印表機)不能接收交叉的資料流。雖然印表機只能一次列印一個任務,但是可能多個程式希望併發列印而不將其輸出混在一起。作業系統通過擷取對印表機的輸出來解決這一問題。應用程式的輸出先是假離線到一個獨立的磁碟檔案上。當應用程式完成列印時,假離線系統將對相應的待送印表機的假離線檔案進行排隊。假離線系統一次複製一個已排隊的假離線檔案到印表機上。有的作業系統採用系統守護程序來管理假離線,而有的作業系統採用核心執行緒來處理假離線。不管怎麼樣,作業系統都提供了一個控制介面以便使用者和系統管理員來顯示佇列,刪除那些尚未列印的而不再需要的任務,當印表機工作暫停列印等。

錯誤處理

    採用記憶體保護的作業系統可以預防許多硬體和應用程式的錯誤,這樣就不會應為小的機械失靈導致系統崩潰。裝置和I/O傳輸的出錯有多種方式,有的短暫,如網路過載;有的永久,如磁碟控制器缺陷。作業系統可以對短暫的出錯進行彌補。

I/O保護

    錯誤與保護息息相關。通過發出非法I/O指令,使用者程式可以有意或無意地中斷系統的正常操作。可使用各種機制以確保這種中斷不會發生。

    為了防止使用者執行非法I/O,定義所有I/O指令為特權指令。因此,使用者不能直接發出I/O指令,它們必須通過作業系統來進行。要進行I/O,使用者程式執行系統呼叫來請求作業系統代表使用者執行I/O操作。如下圖所示,作業系統在監控模式下,檢查請求是否合法,如合法,則處理I/O請求,然後返回給使用者。

另外,所有記憶體對映和I/O埠記憶體位置都受到記憶體保護系統的保護,以阻止使用者訪問。注意,核心不能簡單地拒絕所有使用者訪問。

核心資料結構

    核心需要儲存I/O元件使用的狀態資訊,可以通過若干核心資料結構如檔案開啟表等來完成。核心使用許多類似地結構來跟蹤網路連線,字元裝置通訊和其他I/O活動等。

    UNXI提供對若干實體,如用檔案、原裝置和程序地址空間的檔案系統訪問。有的作業系統更為廣泛地使用了面向物件方法。例如,Windows NT的I/O採用訊息傳遞來實現。一個I/O請求首先轉換成一條訊息,然後再通過核心傳遞給I/O管理器,再到裝置驅動程式。

核心I/O子系統小結

    總而言之,I/O子系統為應用程式和核心其他部分提供了一個可擴充套件的服務集合,I/O子系統負責:

  • 檔案和裝置的名稱空間的管理
  • 檔案和裝置的訪問控制
  • 操作控制(例如,調變解調器不能使用seek())
  • 檔案系統空間分配
  • 裝置分配
  • I/O排程
  • 裝置狀態監控,錯誤處理以及失敗恢復。
  • 裝置驅動程式的配置和初始化

把I/O操作轉換成硬體操作

    以上描述裝置驅動程式與裝置控制器之間的握手,但還沒有解釋作業系統是如何將應用程式的請求與網路線路或特定磁碟扇區連線起來。這裡以磁碟讀檔案為例來考慮這一問題。應用程式通過檔名來訪問資料。對於一個磁碟,檔案系統通過檔案目錄從檔名進行對映,從而得到檔案的空間分配。

    檔名到磁碟控制器(硬體埠地址或記憶體對映控制器暫存器)的連線是如何建立的呢?首先來看一個相對簡單的作業系統MS-DOS。MS-DOS檔名在冒號前的部分是一個字串,用來表示特定硬體裝置。裝置名稱空間有別於每個裝置內檔案系統的名稱空間。這一區別有助於作業系統將額外功能與每個裝置相連。

    如果裝置名稱空間整合到普通檔案系統的名稱空間,如UNIX,那麼就自動提供了普通檔案系統名稱服務。如果檔案系統提供對所有檔名稱進行所有權和訪問控制,那麼裝置就有所有權的訪問控制。由於檔案儲存在裝置上,這種介面提供對I/O系統的雙層訪問。名稱能用來訪問裝置,也用來訪問儲存在裝置上的檔案。

    UNIX通過普通檔案系統名稱空間來給裝置命名。與MS-DOS檔名稱不一樣(即有冒號分隔符),UNIX路勁名並不區別裝置部分。事實上,路勁名中沒有裝置名稱。UNIX中有一個裝配表(mount table),用來將路勁名的字首與特定裝置名稱相連。為了解析路勁名,UNIX檢查裝配表內的名稱以找到最長的匹配字首,裝配表內相應條目就給來了裝置名稱。該裝置名稱在檔案系統名稱空間內也有一個名稱。當UNIX在檔案系統目錄結構內查詢該名稱時,得到的不是inode號,而是裝置號<主,次>。主裝置號表示處理該裝置I/O的裝置驅動程式。次裝置號傳遞給裝置驅動程式以查詢裝置表。裝置表內的相應條目會給出裝置控制器的埠地址或記憶體對映地址。

    現代作業系統通過對請求與物理裝置控制器之間的多級表查詢,可以獲得巨大的靈活性。應用程式與驅動程式之間的請求傳遞機制是通用的。因此,不必重新編譯核心也能為計算機引入新裝置和新驅動程式。事實上,有的作業系統能夠按需載入裝置驅動程式,在啟東時,系統首先檢測硬體匯流排與確定有哪些裝置,接著作業系統就馬上或等首次I/O請求時裝入所需的驅動程式。

    下圖描述了阻塞讀請求的典型週期。

  1. 一個程序對已開啟檔案的檔案描述符呼叫阻塞read()系統呼叫。
  2. 核心系統呼叫程式碼檢查引數是否正確,對於輸入,如果資料已在快取記憶體中,那麼就將該資料返回給程序並完成I/O請求。
  3. 否則,就需要執行物理I/O請求。這時,該程序會從執行佇列移到裝置的等待佇列,並排程I/O請求。最後I/O子系統對裝置驅動程式發出請求。根據作業系統的不同,該請求可能通過子程式呼叫或核心訊息傳遞。
  4. 裝置驅動程式分配核心緩衝空間以接收資料,並排程I/O。最後,裝置驅動程式通過寫入裝置控制器暫存器來對裝置控制器傳送命令。
  5. 裝置控制器控制裝置硬體以執行資料傳輸。
  6. 驅動程式可以輪詢檢測狀態和資料,或通過設定DMA將資料傳入到核心記憶體。假定DMA控制器管理傳輸,當傳輸完成後會產生中斷。
  7. 合適的中斷處理程式通過中斷向量表收到中斷,儲存必要的資料,並向核心裝置驅動程式傳送訊號通知,然後從中斷返回。
  8. 裝置驅動程式接收訊號,確定I/O請求是否完成,確定請求狀態,並向核心I/O子系統傳送訊號,通知請求已完成。
  9. 核心將資料或返回程式碼傳遞請求程序的地址空間,將程序從等待佇列移到就緒佇列。
  10. 將程序移到就緒佇列會使該程序不再阻塞。當排程器給該程序分配CPU時,該程序就繼續在系統呼叫完成後繼續執行。

效能

    I/O是影響系統性能的重要因素之一。執行裝置驅動程式程式碼以及隨著程序阻塞變化而公平且高效地排程程序,這些都增加了CPU的負荷。由此而產生的上下文切換也增加了CPU及其硬體快取記憶體的負擔。I/O暴露出核心中斷機制的任何效率缺陷。

小結

    相關I/O硬體的基本要素是匯流排裝置控制器裝置本身。裝置與記憶體間的資料傳輸工作由CPU按程式控制I/O完成,或轉交給DMA控制器。控制裝置的記憶體模組稱為裝置驅動程式。提供給應用程式的系統呼叫介面用於處理若干基本型別的硬體,包括塊裝置、字元裝置、記憶體對映檔案、網路Socket、可程式設計間隔定時器。系統呼叫通常會使呼叫程序阻塞,但是非阻塞和非同步呼叫可以為核心自己使用,也可為不能等待I/O操作完成的應用程式所使用。

    核心I/O子系統提供了若干服務。其中有I/O排程、緩衝、快取記憶體、假離線、裝置預留以及出錯處理。另一個服務是名稱轉換,即在硬體裝置和應用程式所用的符號檔名之間建立連線。這包括多級對映,用來將字元檔名稱對映到特定裝置驅動程式和裝置地址,然後到I/O埠和匯流排控制器的實體地址。這一對映可以發生在檔案系統名稱空間內,如UNIX,也可以出現在獨立的裝置名稱空間內,如MS-DOS。

    流是使得裝置驅動程式可以重用和更容易使用的一種實現方法。通過流,驅動程式可以堆疊,資料可以按單向和雙向來傳輸和處理。

    由於物理裝置和應用程式之間的多層軟體,I/O系統呼叫所用的CPU週期較多。這些層帶來了多種開銷,如穿過核心保護邊界的上下文切換,用於I/O裝置的訊號和中斷處理,用於核心緩衝區和應用程式之間的資料複製所需的CPU和記憶體系統的負荷。