作業系統是如何訪問IO裝置的?

作業系統訪問IO裝置的過程,經歷過很多個層次,就像網路層協議一樣,每一層幹每一層的事情,每一層又向上層提供介面,作業系統訪問IO裝置的層次結構如下圖所示:

作業系統是如何訪問IO裝置的?

IO結構層次

因此,本篇文章分為5個部分,逐步闡述作業系統訪問IO裝置的過程

IO裝置分類

裝置控制器

裝置驅動程式

核心IO子系統

作業系統控制IO裝置的流程舉例

IO裝置分類:

IO裝置大致分為塊裝置,字元裝置,網路裝置,定時器等,本篇文章主要關注的是塊裝置,字元裝置,網路裝置,這些裝置是我們程式開發中經常涉及的部分。

塊裝置:

塊裝置將資料分隔成多個固定大小的塊進行儲存,塊是資料儲存的最小單位,每個塊的大小可以為512位元組-65536位元組,每個塊都有唯一的地址,因此塊裝置是可以定址的,每次讀寫塊裝置的資料時,都是以塊為最小單位讀取或者寫入連續的多個塊。

例如磁碟就是塊裝置,它的塊大小通常是512個位元組等於磁碟的一個扇區的大小,因此一個扇區就是一個塊,磁碟的資料是由很多個扇區構成。

通常塊裝置可以順序訪問或者隨機訪問,應用程式訪問塊裝置時,通常不是直接訪問的,而是透過檔案系統,檔案系統對塊裝置進行統一管理,將塊裝置的各類細節封裝起來,檔案系統管理的是邏輯裝置即檔案,檔案系統統一提供read,write,seek等介面間接訪問塊裝置,檔案系統將檔名和塊裝置的每一個塊之間的對映關係隱藏起來,因此塊裝置對於應用程式來說是透明。

當然有些特殊的應用程式例如資料庫管理系統可以直接訪問塊裝置,對塊裝置的每個塊採用專用的資料結構進行管理,以達到最佳的讀寫效率,這些專用的資料結構有B+樹,LSVM樹等,這些資料結構都有各自的應用場景。

字元裝置:

字元裝置是不可以儲存和不可以定址的,字元裝置每次讀入或者寫入一個字元,常見的字元裝置包括滑鼠,鍵盤,印表機等,作業系統通常會提供一些get或者put的方法來讀取或者寫入一個位元組,通常會有標準庫對作業系統提供的get或者put方法進行封裝,例如增加了字元緩衝,支援字元流讀寫,支援按行讀,按行寫,編輯緩衝資料等。

網路裝置:

網路裝置通常用於傳送或者接受網路資料,這些網路資料通常是網路包的形式,不同於塊裝置,作業系統會提供專門的網路介面進行網路資料的傳送和接受,網路介面通常就是Socket,這個socket是傳輸層協議的代理,我們透過socket就可以處理網路資料了。

對於Socket它就像一個電源插座,任何電器都可以插入電源插座,一旦插入電源插座就可以通電,因此應用程式也可以用建立一個Socket,Socket分為服務端Socket和客戶端Socket,服務端Socket啟動後,會一直監聽來自客戶端Socket的來電,一旦接到來電就可以轉給一個接線員,這個接線員也是一個Socket,由它來負責與客戶端Socket的通訊。

Socket通常支援BIO,NIO,AIO幾種模式,不同的作業系統支援的模式不同,通常都支援BIO和NIO,根據不同的應用場景可以選擇不同的模式,沒有絕對可言。

定時器:

定時器通常分為硬定時器和軟定時器。

硬定時器:

硬定時器通常是由晶體震盪器,計數器和儲存暫存器組成,當把一塊石英晶體適當地切割後,並在它上加上一定的電壓後,它就可以非常精確地產生週期性的時鐘訊號,這些訊號的頻率可以是幾百赫茲,幾千赫茲等,這個頻率值跟所選的晶體型別有關。

硬定時器的基本原理是這樣的:

每個定時器會在儲存暫存器設定一個計數值,每次定時器啟動時,將這個計數值設定到計數器中,每次晶體震盪後,產生一個時鐘訊號,該訊號被送入到計數器,計數器就減1,直到計數器變為0,那就表示定時器觸發了,它會給CPU傳送一個時鐘中斷,CPU接收到這個中斷後會進入時鐘處理程式。

時鐘處理程式會進行一些防止程序時間片超時,程序CPU使用情況記賬,維護計算機時間,計算機硬體監控,程序效能資料剖析等工作。

硬體定時器可以分為一次性定時器和永久性定時器,一次性定時器表示定時器觸發後後,就自動停止了,永久性定時器則每次定時器觸發後,會將儲存暫存器中的計數值重新賦值給計數器,然後重新啟動定時器,一直執行,直到計算機關閉。

軟定時器:

有些高效能的工作需要高頻率地執行,例如一個高效能的網路,網路頻寬為千兆級別以上,為了保證高效率地輸出,每隔12us就要傳送一個數據包,如果採用硬定時器,每隔12us產生中斷後,會進行一系列的處理,包括程序上下文,流水線,高速緩衝,TLB,MMU等重新切換等,這一繁雜的切換工作需要的時間可能已經接近12us,那麼這就意味著從中斷開始到真正開始傳送資料包,會經過一段時間,這個時間對於一個高效能的網路來說是不能容忍的,因此這種場景可以採用軟定時器,軟定時器不需要中斷,每次傳送資料包時,會根據硬定時器+12us設定一個超時時間,每次傳送完資料包切換到使用者態後,使用者程式檢查這個超時時間是不是已經過期了,如果過期了就立即傳送一個數據包,對於這類高效能的場景,軟定時器比較合適,當然如果沒有要求那麼高的效能要求的話,一般的硬定時器中斷足夠應付了。

裝置控制器:

作業系統是不直接操作IO裝置,常常是透過裝置控制器間接訪問IO裝置,可以說裝置控制器是CPU與IO裝置的橋樑,裝置控制器可以連線單個裝置,也可以同時連線多個裝置,如果連線多個裝置,裝置控制器和裝置之間需要增加一個仲裁裝置,這個仲裁裝置負責仲裁裝置控制器要和那個IO裝置進行互動。

裝置控制器負責的工作如下:

負責控制IO裝置,例如裝置的讀,寫,開啟,關閉等。

協調CPU和IO裝置速度讀寫速度的不匹配,例如裝置控制器增加資料緩衝。

CPU和IO裝置資料訊號的轉換。

CPu時鐘頻率和IO裝置時鐘頻率的協調和同步。

IO埠地址的譯碼,例如翻譯IO埠地址到具體的裝置暫存器。

裝置控制器提供了4種暫存器即狀態暫存器,資料輸入暫存器,資料輸出暫存器,控制暫存器,作業系統和裝置控制器之間的互動就是透過這些裝置暫存器,因此它們的互動方式類似於生產者和消費者的關係。

資料輸出暫存器:

作業系統可以將CPU暫存器的資料傳送到資料輸出暫存器,裝置控制器得知資料輸出暫存器有資料後,就將資料輸出暫存器的資料傳送給IO裝置。

資料輸入暫存器:

裝置控制器讀入IO裝置的資料後,儲存在資料輸入暫存器,然後作業系統讀取資料輸入暫存器的資料到CPU暫存器中。

狀態暫存器:

儲存裝置相關的狀態,例如裝置是否已經就緒,資料輸入暫存器是不是有資料了等,作業系統可以讀取該暫存器的值來檢視裝置的各類狀態。

控制暫存器:

作業系統可以寫入控制暫存器從而告知裝置控制器執行什麼IO操作。

另外,為了協調CPU和IO裝置的讀寫速度差異,裝置控制器通常有資料緩衝,用於緩衝從裝置讀入的資料,或者從作業系統寫入的資料,例如作業系統將資料寫入到資料輸出暫存器後,裝置控制器將資料輸出暫存器的資料直接寫入到資料緩衝,而不是直接傳送到IO裝置,這個很好理解,因為裝置控制器寫入資料到IO裝置的速度與CPU的傳送速度相比差異太大了。

作業系統怎麼讀寫裝置暫存器呢,有兩種方式

1.IO指令

每個裝置暫存器都有一個地址,它與記憶體的地址不同,這個地址稱為IO埠地址,作業系統支援的IO埠地址有65536個即0~64K-1,IO埠地址的範圍叫做IO埠空間,記憶體地址範圍叫做記憶體空間,因此IO埠空間與記憶體空間是獨立的。

假如CPU要讀取一個埠地址對應裝置暫存器,過程如下:

1。CPU將IO埠地址放到地址總線上,然後在控制總線上設定一個READ訊號,此時只是CPU只是要表明要讀取某個地址的資料了,至於這個地址來自哪個空間,還需要下一步操作。

2。CPU裝置另外一條訊號線,設定訊號線要訪問IO埠空間。

3。所有的裝置控制器接收到該訊號線後,發現是訪問IO埠空間,就會檢查地址總線上的地址是不是自己的暫存器的地址,總有一個裝置控制器接受這個地址,不是自己的地址裝置控制器直接忽略這個訊號。

下面表格為PC裝置中常見的裝置IO埠地址分佈圖

IO埠範圍(十六進位制)

裝置

000-00F

DMA控制器

020-021

中斷控制器

200-20F

遊戲控制器

320-32F

硬碟控制器

3D0-3DF

圖形控制器

3F0-3F7

軟盤控制器

另外,CPU提供了專門的IO指令,透過IO指令傳送內容到IO埠地址或者從IO埠地址獲取內容來實現裝置暫存器的讀寫,

常見的IO指令有IN和OUT

IN AX,DX

DX暫存器儲存的是IO埠,該指令表示獲取IO埠指向的裝置暫存器的內容到AX暫存器。

OUT DX,AX

DX暫存器儲存的IO埠,該指令表示將AX暫存器的內容寫入到IO埠指向的裝置暫存器。

2.記憶體對映IO

CPU訪問任何資料都是透過地址匯流排,一個32位的地址匯流排可以定址的範圍是4個G,從上文知道,如果有IO埠地址空間的話,需要單獨的一個訊號線表明地址線訪問的那個空間,假設該訊號線訪問的是記憶體空間。

這個記憶體空間內大部分地址分給了主存,還有一小部分地址落在了其它的記憶體或者裝置暫存器,例如圖形控制器的資料緩衝,BIOS的ROM等,通常這部分地址在地址匯流排範圍的低地址處,如下圖

作業系統是如何訪問IO裝置的?

記憶體對映IO

因此透過記憶體對映IO,我們不需要專門的IO指令,直接透過記憶體相關的指令例如MOV,LOAD等命令就可以讀寫裝置暫存器或者裝置控制器的資料緩衝,當地址總線上寫入了地址後,主存,裝置控制器,BIOS等都會檢查這個地址是不是屬於自己的範圍,如果是自己的範圍內的地址,就會接受這個地址,並且做出響應。

作業系統與裝置控制器互動的方式通常有3種:

程式控制IO

程式控制IO也叫輪詢,假設CPU寫資料到IO裝置,通常應用程式會在使用者空間分配一個緩衝,使用者緩衝要傳送的資料,然後進行系統呼叫,透過系統呼叫,核心會將使用者緩衝複製到核心緩衝,這個記憶體緩衝可以認為是一個傳送陣列,然後對傳送陣列的每個位元組逐個按照以下流程寫入到IO裝置,流程如下圖所示:

作業系統是如何訪問IO裝置的?

CPU輪詢方式會一直檢查狀態暫存器,一直到狀態暫存器不忙時,才會寫入傳送陣列的當前位元組到資料輸出暫存器,同時設定控制暫存器的寫位和就緒位,通知裝置控制器要執行一個寫操作而且資料已經準備好了。

裝置控制器檢查到控制暫存器的就緒位已經就緒後,會進一步檢查要執行什麼操作,發現寫位為1,就會從資料輸出暫存器獲取資料,寫到IO裝置,完成後,就會清除控制暫存器的就緒位,忙位,故障位,這樣CPU就會繼續寫入資料了。

IO裝置的寫速度與CPU相比差的十萬八千里,因此CPU大部分的時間都在檢查狀態暫存器的忙位,浪費了大量的CPU時間,這也是輪詢方式最大的缺點。

中斷驅動IO

假設CPU寫資料到IO裝置,通常應用程式會在使用者空間分配一個緩衝,使用者緩衝要傳送的資料,然後進行系統呼叫,透過系統呼叫,核心會將使用者緩衝複製到核心緩衝,這個記憶體緩衝可以認為是一個傳送陣列,然後對傳送陣列的每個位元組逐個按照以下流程寫入到IO裝置,假設傳送陣列剩餘要傳送的位元組數為count,如下圖所示為中斷驅動IO的流程圖

作業系統是如何訪問IO裝置的?

由上圖所示分為3個子流程

CPU寫入流程:

CPU寫入流程與輪詢看起來有點類似,不一樣的地方在於,使用者程序在寫入第一個資料到暫存器後,就被阻塞了,CPU此時排程其它程序執行。

裝置控制器流程:

這個流程與輪詢中的裝置控制器流程比較類似,不同的是,裝置控制器寫資料到IO裝置後,會發送一個裝置中斷訊號給CPU,通知CPU可以繼續傳送資料了。

CPU中斷處理程式:

每次CPU執行時,會先檢查中斷線上是不是有中斷訊號,如果有中斷訊號,就會去執行中斷處理程式,對於裝置的中斷處理程式,如果沒有傳送的資料了,就將使用者程序加入到CPU的就緒佇列中,CPU後續會排程使用者程序,阻塞就解除了,呼叫就返回了,如果有傳送的資料,就繼續傳送到裝置控制器的暫存器中。

中斷處理程式返回後,會被切換到被中斷的程序,繼續執行。

中斷驅動IO相比輪詢來說,不需要CPU一直等IO裝置寫入完成,而是可以將寫入暫存器後,直接阻塞,排程其它的程序來使用CPU,當IO裝置寫入完成後,傳送中斷訊號,通知CPU,CPU執行中斷處理程式繼續寫入下一個位元組,最終傳送完成後,解除阻塞,這樣CPU就可以充分利用,減少了CPU的浪費。

DMA

假設CPU寫資料到IO裝置,通常應用程式會在使用者空間分配一個緩衝,使用者緩衝要傳送的資料,然後進行系統呼叫,透過系統呼叫,核心會將使用者緩衝複製到核心緩衝,這個記憶體緩衝可以認為是一個傳送陣列。

DMA的處理流程如下:

作業系統是如何訪問IO裝置的?

DMA

DMA的處理流程也可以分為3個子流程

CPU流程 :

CPU傳輸傳送陣列的起始地址,傳送陣列的大小給DMA,此時使用者程序A就從CPU執行佇列移除,此時使用者程序A阻塞,CPU排程其它的程序執行。

DMA流程:

DMA根據傳送陣列的起始地址,檢查尚未傳送的位元組數count,如果count<0, 那麼就是傳輸資料給裝置暫存器,然後就等待裝置控制器的應答,如果 count=0,那麼DMA傳送完成了,它會給CPU傳送一箇中斷訊號,CPU收到這個中斷訊號後,會執行DMA的中斷處理程式,將使用者程序A加入到CPU的就緒佇列,後續CPU會排程使用者程序A去執行,這個時候使用者程序A呼叫返回。

裝置控制器流程:

裝置控制器的流程與輪詢和中斷類似,只是裝置控制器傳送完資料後,會發送一個應答給DMA,DMA收到這個應答後,會將coun-1,然後排程傳送下一個位元組。

可以看出DMA不需要裝置控制器傳送中斷給CPU,它成為了CPU的代理,CPU可以專注地做其它的事情,只是DMA傳輸完成後,才會中斷一下CPU。

另外DMA每次控制裝置控制器寫資料時,都會先控制住地址匯流排,這樣就會跟CPU搶時鐘週期,這個也是不可以避免的。

DMA控制器可以連線多個裝置控制器,透過一定的演算法,來切換每次控制的裝置控制器,另外複雜一些的DMA控制器也可以一次控制裝置控制器傳送多個位元組,這樣一次性佔據地址匯流排的時間就比較長,這樣的效率也會更高,只是CPU如果此時需要用地址匯流排,那就需要等待一段時間了,CPU週期被浪費了。

裝置驅動程式

我們上面闡述作業系統透過控制裝置控制器來間接控制IO裝置,其實就是裝置驅動程式來控制裝置控制器。

裝置驅動程式通常位於核心,它封裝對裝置控制器操作的所有細節和差異,並且提供了標準的介面供核心的IO子系統呼叫,這一點類似於網路協議的分層結構,每一層將資料封裝好後提供給上一層使用,上一層不用考慮下一層的實現細節。

可以說裝置驅動程式將硬體和IO子系統呼叫分離開來,每一類裝置都需要專門的裝置驅動程式進行控制,一般這些裝置驅動程式都是由裝置提供商來負責編寫,通常不同的作業系統裝置驅動程式都有不同的開發標準,因此只要裝置提供商按照作業系統要求的標準開發裝置驅動程式,增加任何的IO裝置和控制器對於作業系統來說都是透明的,當然這對作業系統來說好處多多,對於裝置提供商來說好處不多,他們需要為各種作業系統系統編寫驅動程式,這樣才能爭取不同作業系統的使用者。

通常裝置驅動程式不新增任何使用者策略,只負責與硬體打交道,它通常會將上層IO子系統傳送過來的抽象的讀寫請求,轉化為實際的對硬體的IO操作,保證硬體可用並提供硬體原始資料,原始的資料交由IO子系統進行二次加工,IO子系統再根據根據各類使用者策略對原始資料進行處理。

IO子系統

IO子系統位於核心,處於裝置驅動程式的上一層,它是裝置無關的,主要提供檔案系統,IO排程,緩衝,高速緩衝,裝置保護,錯誤處理等。

增加新的裝置驅動程式對IO子系統沒有i影響,因為每個裝置驅動程式向IO子系統提供標準的訪問介面。

檔案系統:

檔案系統主要負責對塊裝置進行統一管理,抽象出文件這個邏輯裝置的概念,建立檔案與塊裝置的每個塊的對映關係等,檔案系統也負責根據檔名定位到裝置驅動程式和具體的某個裝置,這個以後單獨寫文章闡述。

IO排程

作業系統為每個裝置維護一個IO請求佇列,當程序進行IO請求時,會將這些IO請求加入到這個佇列中,如果按照先進先出的方式順序訪問裝置,從系統總體來講,並不一定是高效的,通常需要合適的IO排程演算法來高效和充分地利用裝置。

另外不同的IO請求有不同的優先順序,有些IO請求優先順序天生比較高,它可以獲得優先執行的權利,例如一個缺頁IO請求就比其它的普通應用程式的請求更加緊急,也會有更高的優先順序。

緩衝

採用緩衝有以下幾個理由:

一:

裝置控制器通常有單獨的資料緩衝,應用程式也需要有自己的緩衝,應用程式寫資料時,通常寫入到自己的緩衝,而不是直接寫到裝置控制器的緩衝,這是由於IO裝置處理資料較慢,裝置控制器的緩衝,很容易就滿了,因此應用程式設定自己的緩衝,這樣即使裝置控制器緩衝滿了,應用程式照樣可以寫資料,不至於阻塞,另外應用程式設定自己的緩衝,可以靈活增加緩衝的容量,也可以設定多個緩衝,例如雙緩衝,迴圈緩衝等。

。通常應用程式自己的緩衝在使用者空間,作業系統可以將使用者緩衝中的資料傳送到裝置控制器上的資料緩衝,裝置控制器再發送資料緩衝的資料到裝置,這樣有兩個問題,一個是:使用者空間的緩衝通常是在使用者空間的某些頁上,一旦這些頁被換出了,作業系統讀取這些頁的資料時發現頁不在就會進行缺頁處理,這個很影響效率,另外一個是:作業系統傳送資料時,使用者空間的緩衝被修改了,此時就造成了資料的破壞,因此通常作業系統會在核心開闢一塊空間叫做核心緩衝,應用程式寫入資料時,先將使用者緩衝複製到核心緩衝,核心緩衝再寫入到裝置控制器的資料緩衝,此後核心就可以放心地傳送資料了,不用擔心頁被換出或者資料被修改了,這樣的複製非常影響效率,因此有些作業系統會採用虛擬記憶體對映和寫時複製的方式將使用者緩衝和核心緩衝指向核心的一塊共享緩衝,如果使用者修改了共享緩衝,會透過寫時複製的方式,複製修改的部分到使用者空間,不影響原來的共享緩衝。

整體來說緩衝不光是寫出的緩衝,讀入的緩衝也是同樣的道理,這裡不再闡述。

快取記憶體:

作業系統可以開闢一塊記憶體,用於儲存熱點的裝置資料,採用一定的快取失效演算法,剔除失效的快取,這樣可以每次進行IO讀取操作時,則可以直接從快取記憶體中獲取,不在進行任何IO操作。

有時候快取記憶體和緩衝可以合二為一,例如一個寫緩衝儲存了要寫出到裝置的資料,此時如果再讀取這些資料時,就可以把寫緩衝當做高速緩衝,直接從寫緩衝讀取。

裝置保護:

IO裝置保護有以下幾種方式:

1。IO特權指令,IO指令通常都是特權指令,這些指令只有作業系統才可執行,這樣就杜絕了應用程式執行IO指令,應用程式可以透過系統呼叫進行IO操作。

2。透過記憶體對映IO方式訪問裝置控制器資料緩衝或者裝置暫存器時,地址總線上一部分地址用於對映到裝置控制器資料緩衝或者裝置暫存器,這部分地址由作業系統的記憶體保護模組進行控制,禁止使用者空間訪問這些地址。

3。IO子系統中檔案系統中所有的檔案都有訪問的許可權,限制檔案的訪問就間接地對檔案對應的IO裝置進行了保護。

錯誤處理:

IO裝置產生的錯誤往往比較多而且雜,當錯誤發生時,IO子系統會盡最大努力對這些錯誤進行處理,許多IO錯誤與特定的裝置有關,這類的錯誤只能交由裝置驅動程式去處理,但IO子系統有個錯誤處理的流程,按照這個流程進行處理是通用的和裝置無關的,以下為錯誤處理框架中的幾個關鍵環節的處理過程。

一:

一些IO類的錯誤是程式設計導致的,比如應用程式對鍵盤,掃描器,滑鼠進行寫入操作,這些裝置是不支援寫入的,還有就是應用程式提供了一個無效的緩衝區或者引數,這些程式設計導致的錯誤,IO子系統直接返回相應的錯誤碼給應用程式。

二:

另外一種IO類的錯誤就是裝置確實有問題了,例如應用程式試圖寫入一個損壞的磁碟塊,這類錯誤交由裝置驅動程式解決,如果裝置驅動程式實在不知道怎麼解決,則再返回IO子系統,由IO子系統返回給應用程式。

三:

還有一些IO類錯誤可以交由使用者去決定怎麼去解決,例如一個讀磁碟發生錯誤,可以由IO子系統告知使用者,例如彈出一個對話方塊,讓使用者去選擇重試次數,忽略錯誤,或者乾脆停掉程序。

作業系統訪問IO裝置的流程舉例

假設應用程式進行一個系統呼叫read讀取磁碟資料,這個read是阻塞的,裝置驅動程式與裝置控制器互動方式採用DMA,下面來闡述下整個流程如下圖所示:

作業系統是如何訪問IO裝置的?

1.

IO子系統根據檔名可以定位到裝置驅動程式,裝置暫存器埠,磁碟物理地址,每個作業系統有各自的實現方式,通常這一部分通常由檔案系統來實現。

2.

IO子系統根據磁碟物理地址去高速緩衝中查詢,如果高速緩衝命中,則將高速緩衝中的資料複製到使用者空間緩衝,呼叫返回。

5.

IO子系統將應用程式A從CPU的執行佇列移除,加入到裝置的等待佇列,這個時候應用程式阻塞了。

6~8.

IO子系統根據裝置暫存器埠和磁碟物理地址封裝IO請求,將IO請求加入到裝置IO請求佇列中,IO子系統根據IO請求排程演算法,開始呼叫IO請求,最終將應用程序A的IO請求傳送給裝置驅動程式。

9~11.

裝置驅動程式在核心空間開闢一塊記憶體空間,作為核心緩衝,這塊核心緩衝用來接收來自磁碟的資料,然後裝置驅動程式控制DMA,傳送控制請求給DMA,然後裝置驅動程式阻塞了,阻塞的方法有很多中,比如wait。

12

。DMA控制磁碟控制器,完成讀取資料後,傳送中斷訊號給CPU。

13.

CPU接受到中斷訊號後,開始執行中斷處理程式,程式會檢查IO請求是否已經完成,請求的完成狀態等,然後封裝IO請求結果,傳送給IO子系統。

14.

IO子系統收到請求結果後,會喚醒裝置驅動程式,喚醒的方式比如singal,同時IO子系統會複製核心緩衝的資料到使用者緩衝,同時將返回結果設定到應用程式A的使用者空間。

15.

IO子系統將應用程式A從裝置佇列中移除,加入到CPU就緒佇列中。

16.

CPU排程執行應用程序A,應用程序A將返回結果返回。