本文主要是講Linux的調(diào)度系統(tǒng), 由于全部?jī)?nèi)容太多,分三部分來(lái)講,調(diào)度可以說(shuō)是操作系統(tǒng)的靈魂,為了讓CPU資源利用最大化,Linux設(shè)計(jì)了一套非常精細(xì)的調(diào)度系統(tǒng),對(duì)大多數(shù)場(chǎng)景都進(jìn)行了很多優(yōu)化,系統(tǒng)擴(kuò)展性強(qiáng),我們可以根據(jù)業(yè)務(wù)模型和業(yè)務(wù)場(chǎng)景的特點(diǎn),有針對(duì)性的去進(jìn)行性能優(yōu)化,在保證客戶網(wǎng)絡(luò)帶寬前提下,隔離客戶互相之間的干擾影響,提高CPU利用率,降低單位運(yùn)算成本,提高市場(chǎng)競(jìng)爭(zhēng)力。歡迎大家相互交流學(xué)習(xí)!
CPU作為計(jì)算資源,一直是云計(jì)算廠商比拼的核心競(jìng)爭(zhēng)力,我們的目標(biāo)是合理安排好計(jì)算任務(wù),充分提高CPU的利用率,預(yù)留更多空間容錯(cuò),增強(qiáng)系統(tǒng)穩(wěn)定性,讓任務(wù)更快執(zhí)行,降低無(wú)效功耗,節(jié)約成本,從而提高市場(chǎng)競(jìng)爭(zhēng)力。
CPU 實(shí)現(xiàn)的抽象邏輯圖
首先,我們有一個(gè)自動(dòng)計(jì)數(shù)器。這個(gè)自動(dòng)計(jì)數(shù)器會(huì)隨著時(shí)鐘主頻不斷地自增,來(lái)作為我們的 PC 寄存器;
在這個(gè)自動(dòng)計(jì)數(shù)器的后面,我們連上一個(gè)譯碼器。譯碼器還要同時(shí)連著我們通過(guò)大量的 D 觸發(fā)器組成的內(nèi)存。
自動(dòng)計(jì)數(shù)器會(huì)隨著時(shí)鐘主頻不斷自增,從譯碼器當(dāng)中,找到對(duì)應(yīng)的計(jì)數(shù)器所表示的內(nèi)存地址,然后讀取出里面的 CPU 指令。
讀取出來(lái)的 CPU 指令會(huì)通過(guò)CPU 時(shí)鐘的控制,寫入到一個(gè)由 D 觸發(fā)器組成的寄存器,也就是指令寄存器當(dāng)中。
在指令寄存器后面,我們可以再跟一個(gè)譯碼器。這個(gè)譯碼器的作用不再是用于尋址,而是把拿到的指令解析成opcode 和對(duì)應(yīng)的操作數(shù)。
當(dāng)我們拿到對(duì)應(yīng)的 opcode 和操作數(shù),對(duì)應(yīng)的輸出線路就要連接 ALU,開(kāi)始進(jìn)行各種算術(shù)和邏輯運(yùn)算。對(duì)應(yīng)的計(jì)算結(jié)果,則會(huì)再寫回到 D 觸發(fā)器組成的寄存器或者內(nèi)存當(dāng)中。
這里整個(gè)過(guò)程就大概是CPU的一條指令的執(zhí)行過(guò)程。為了加快CPU指令的執(zhí)行速度,CPU在發(fā)展過(guò)程中做了很多優(yōu)化,例如流水線,分支預(yù)測(cè),超標(biāo)量,Hyper-threading,SIMD,多級(jí)cache,NUMA架構(gòu)等, 這里主要關(guān)注Linux的調(diào)度系統(tǒng)。
CPU上下文
Linux 是一個(gè)多任務(wù)操作系統(tǒng),它支持遠(yuǎn)大于 CPU 數(shù)量的任務(wù)同時(shí)運(yùn)行。當(dāng)然,這些任務(wù)實(shí)際上并不是真的在同時(shí)運(yùn)行,而是因?yàn)橄到y(tǒng)在很短的時(shí)間內(nèi),將 CPU 輪流分配給它們,造成多任務(wù)同時(shí)運(yùn)行的錯(cuò)覺(jué)。
而在每個(gè)任務(wù)運(yùn)行前,CPU 都需要知道任務(wù)從哪里加載、又從哪里開(kāi)始運(yùn)行,也就是說(shuō),需要系統(tǒng)事先幫它設(shè)置好 CPU 寄存器和程序計(jì)數(shù)器(Program Counter,PC)。
CPU 寄存器,是 CPU 內(nèi)置的容量小、但速度極快的內(nèi)存。而程序計(jì)數(shù)器,則是用來(lái)存儲(chǔ) CPU 正在執(zhí)行的指令位置、或者即將執(zhí)行的下一條指令位置。它們都是 CPU 在運(yùn)行任何任務(wù)前,必須的依賴環(huán)境,因此也被叫做 CPU 上下文(執(zhí)行環(huán)境):
而這些保存下來(lái)的上下文,會(huì)存儲(chǔ)在系統(tǒng)內(nèi)核中(堆棧),并在任務(wù)重新調(diào)度執(zhí)行時(shí)再次加載進(jìn)來(lái)。這樣就能保證任務(wù)原來(lái)的狀態(tài)不受影響,讓任務(wù)看起來(lái)還是連續(xù)運(yùn)行。
在Linux中,內(nèi)核空間和用戶空間是兩種工作模式,操作系統(tǒng)運(yùn)行在內(nèi)核空間,而用戶態(tài)應(yīng)用程序運(yùn)行在用戶空間,它們代表不同的級(jí)別,而對(duì)系統(tǒng)資源具有不同的訪問(wèn)權(quán)限。
這樣代碼(指令)執(zhí)行存在不同的CPU上下文,而進(jìn)行調(diào)度的時(shí)候,要進(jìn)行相應(yīng)的CPU上下文切換,Linux系統(tǒng)存在不同堆棧來(lái)保存CPU上下文,系統(tǒng)中每個(gè)進(jìn)程都會(huì)擁有屬于自己的內(nèi)核棧,而系統(tǒng)中每個(gè)CPU都將為中斷處理準(zhǔn)備了兩個(gè)獨(dú)立的中斷棧,分別是hardirq棧和softirq棧:
Linux系統(tǒng)調(diào)用CPU上下文切換堆棧結(jié)構(gòu):
中斷上下文:中斷代碼運(yùn)行于內(nèi)核空間,中斷上下文即運(yùn)行中斷代碼所需要的CPU上下文環(huán)境,需要硬件傳遞過(guò)來(lái)的這些參數(shù),內(nèi)核需要保存的一些其他環(huán)境(主要是當(dāng)前被打斷執(zhí)行的進(jìn)程或其他中斷環(huán)境),這些一般都保存在中斷棧中(x86是獨(dú)立的,其他可能和內(nèi)核棧共享,這和具體處理架構(gòu)密切相關(guān)),在中斷結(jié)束后,進(jìn)程仍然可以從原來(lái)的狀態(tài)恢復(fù)運(yùn)行。
進(jìn)程上下文:進(jìn)程是由內(nèi)核來(lái)管理和調(diào)度的,進(jìn)程的切換發(fā)生在內(nèi)核態(tài),進(jìn)程的上下文不僅包括了虛擬內(nèi)存、棧、全局變量等用戶空間的資源,還包括了內(nèi)核堆棧、寄存器等內(nèi)核空間的狀態(tài)。
系統(tǒng)調(diào)用上下文:進(jìn)程可以在內(nèi)核空間和用戶空間運(yùn)行,分別稱為進(jìn)程的用戶態(tài)和進(jìn)程的內(nèi)核態(tài), 從用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)變需要通過(guò)系統(tǒng)調(diào)用來(lái)完成,需要進(jìn)行CPU上下文切換,在執(zhí)行系統(tǒng)調(diào)用時(shí)候,需要保存用戶態(tài)的CPU上下文(用戶態(tài)堆棧)到內(nèi)核堆棧,然后加載內(nèi)核態(tài)的CPU上下文。
CPU處理器總處于以下?tīng)顟B(tài)中的一種:
1、內(nèi)核態(tài),運(yùn)行于進(jìn)程上下文,內(nèi)核代表進(jìn)程運(yùn)行于內(nèi)核空間;
2、內(nèi)核態(tài),運(yùn)行于中斷上下文,內(nèi)核代表硬件運(yùn)行于內(nèi)核空間;
3、用戶態(tài),運(yùn)行于用戶空間。
中斷
中斷是由硬件設(shè)備產(chǎn)生的,而它們從物理上說(shuō)就是電信號(hào),之后,它們通過(guò)中斷控制器發(fā)送給CPU,接著CPU判斷收到的中斷來(lái)自于哪個(gè)硬件設(shè)備(這定義在內(nèi)核中),最后,由CPU發(fā)送給內(nèi)核,內(nèi)核來(lái)處理中斷。
硬中斷簡(jiǎn)單處理流程:
硬中斷實(shí)現(xiàn):中斷控制器+中斷服務(wù)程序
中斷框架設(shè)計(jì)(x86):
X86計(jì)算機(jī)的 CPU 為中斷只提供了兩條外接引腳:NMI 和 INTR。其中 NMI 是不可屏蔽中斷,它通常用于電源掉電和物理存儲(chǔ)器奇偶校驗(yàn);INTR是可屏蔽中斷,可以通過(guò)設(shè)置中斷屏蔽位來(lái)進(jìn)行中斷屏蔽,它主要用于接受外部硬件的中斷信號(hào),這些信號(hào)由中斷控制器傳遞給 CPU。當(dāng)前x86 SMP架構(gòu)主流都是采用多級(jí)I/O APIC(高級(jí)可編程中斷控制器)中斷系統(tǒng)。
Local APIC:主要負(fù)責(zé)傳遞中斷信號(hào)到指定的處理器;
I/O APIC:主要是收集來(lái)自 I/O 裝置的 Interrupt 信號(hào)且在當(dāng)那些裝置需要中斷時(shí)發(fā)送信號(hào)到本地 APIC;
中斷分類:
中斷可分為同步(synchronous)中斷和異步(asynchronous)中斷:
同步中斷是當(dāng)指令執(zhí)行時(shí)由 CPU 控制單元主動(dòng)產(chǎn)生,之所以稱為同步,是因?yàn)橹挥性谝粭l指令執(zhí)行完畢后 CPU 才會(huì)發(fā)出中斷,而不是發(fā)生在代碼指令執(zhí)行期間,比如系統(tǒng)調(diào)用,根據(jù) Intel 官方資料,同步中斷稱為異常(exception),異常可分為故障(fault)、陷阱(trap)、終止(abort)三類。
異步中斷是指由其他硬件設(shè)備依照 CPU 時(shí)鐘信號(hào)隨機(jī)產(chǎn)生,即意味著中斷能夠在指令之間發(fā)生,例如鍵盤中斷,異步中斷被稱為中斷(interrupt),中斷可分為可屏蔽中斷(Maskable interrupt)和非屏蔽中斷(Nomaskable interrupt)。
非屏蔽中斷(Non-maskable interrupts,即NMI):就像這種中斷類型的字面意思一樣,這種中斷是不可能被CPU忽略或取消的。NMI是在單獨(dú)的中斷線路上進(jìn)行發(fā)送的,它通常被用于關(guān)鍵性硬件發(fā)生的錯(cuò)誤,如內(nèi)存錯(cuò)誤,風(fēng)扇故障,溫度傳感器故障等。
可屏蔽中斷(Maskable interrupts):這些中斷是可以被CPU忽略或延遲處理的。當(dāng)緩存控制器的外部針腳被觸發(fā)的時(shí)候就會(huì)產(chǎn)生這種類型的中斷,而中斷屏蔽寄存器就會(huì)將這樣的中斷屏蔽掉。我們可以將一個(gè)比特位設(shè)置為0,來(lái)禁用在此針腳觸發(fā)的中斷。
處理流程:
區(qū)別:
相同點(diǎn):
1.最后都是由CPU發(fā)送給內(nèi)核,由內(nèi)核去處理;
2.處理程序的流程設(shè)計(jì)上是相似的。
不同點(diǎn):
1.產(chǎn)生源不相同,陷阱、異常是由CPU產(chǎn)生的,而中斷是由硬件設(shè)備產(chǎn)生的;
2.內(nèi)核需要根據(jù)是異常,陷阱,還是中斷調(diào)用不同的處理程序;
3.中斷不是時(shí)鐘同步的,這意味著中斷可能隨時(shí)到來(lái);陷阱、異常是CPU產(chǎn)生的,所以,它是時(shí)鐘同步的;
4.當(dāng)處理中斷時(shí),處于中斷上下文中;處理陷阱、異常時(shí),處于進(jìn)程上下文中。
中斷親和:
在 SMP 體系結(jié)構(gòu)中,我們可以通過(guò)系統(tǒng)調(diào)用和一組相關(guān)的宏來(lái)設(shè)置 CPU 親和力(CPU affinity),將一個(gè)或多個(gè)進(jìn)程綁定到一個(gè)或多個(gè)處理器上運(yùn)行。中斷在這方面也毫不示弱,也具有相同的特性。中斷親和力是指將一個(gè)或多個(gè)中斷源綁定到特定的 CPU 上運(yùn)行;
在 /proc/irq 目錄中,對(duì)于已經(jīng)注冊(cè)中斷處理程序的硬件設(shè)備,都會(huì)在該目錄下存在一個(gè)以該中斷號(hào)命名的目錄 IRQ# ,IRQ# 目錄下有一個(gè) smp_affinity 文件(SMP 體系結(jié)構(gòu)才有該文件),它是一個(gè) CPU 的位掩碼,可以用來(lái)設(shè)置該中斷的親和力, 默認(rèn)值為 0xffffffff,表明把中斷發(fā)送到所有的 CPU 上去處理。如果中斷控制器不支持 IRQ affinity,不能改變此默認(rèn)值,同時(shí)也不能關(guān)閉所有的 CPU 位掩碼,即不能設(shè)置成 0x0;
中斷親和好處是,在大量硬件中斷場(chǎng)景,對(duì)于文件服務(wù)器、高流量 Web 服務(wù)器這樣的應(yīng)用來(lái)說(shuō),把不同的網(wǎng)卡 IRQ 均衡綁定到不同的 CPU 上將會(huì)減輕某個(gè) CPU 的負(fù)擔(dān),提高多個(gè) CPU 整體處理中斷的能力;對(duì)于數(shù)據(jù)庫(kù)服務(wù)器這樣的應(yīng)用來(lái)說(shuō),把磁盤控制器綁到一個(gè) CPU、把網(wǎng)卡綁定到另一個(gè) CPU 將會(huì)提高數(shù)據(jù)庫(kù)的響應(yīng)時(shí)間,優(yōu)化性能。合理的根據(jù)自己的生產(chǎn)環(huán)境和應(yīng)用的特點(diǎn)來(lái)平衡 IRQ 中斷有助于提高系統(tǒng)的整體吞吐能力和性能;
Linux系統(tǒng)常見(jiàn)中斷分類
時(shí)鐘中斷:時(shí)鐘芯片產(chǎn)生,主要工作是處理和時(shí)間有關(guān)的所有信息,決定是否執(zhí)行調(diào)度程序以及處理下半部分。和時(shí)間有關(guān)的所有信息包括系統(tǒng)時(shí)間、進(jìn)程的時(shí)間片、延時(shí)、使用CPU的時(shí)間、各種定時(shí)器,進(jìn)程更新后的時(shí)間片為進(jìn)程調(diào)度提供依據(jù),然后在時(shí)鐘中斷返回時(shí)決定是否要執(zhí)行調(diào)度程序。下半部分處理程序是Linux提供的一種機(jī)制,它使一部分工作推遲執(zhí)行。時(shí)鐘中斷要絕對(duì)保證維持系統(tǒng)時(shí)間的準(zhǔn)確性,“時(shí)鐘中斷”是整個(gè)操作系統(tǒng)的脈搏。
NMI中斷:外部硬件通過(guò)CPU的 NMI Pin 去觸發(fā)(硬件觸發(fā)),或者軟件向CPU系統(tǒng)總線上投遞一個(gè)NMI類型中斷(軟件觸發(fā)),NMI中斷的主要用途有兩個(gè):
用來(lái)告知操作系統(tǒng)有硬件錯(cuò)誤(Hardware Failure),如內(nèi)存錯(cuò)誤,風(fēng)扇故障,溫度傳感器故障等;
用來(lái)做看門狗定時(shí)器,檢測(cè)CPU死鎖等;
硬件IO中斷:
大多數(shù)硬件外設(shè)IO中斷,比如網(wǎng)卡,鍵盤,硬盤,鼠標(biāo),USB,串口等;
虛擬中斷:
KVM里面一些中斷退出和中斷注入等,軟件模擬中斷;
查看方式:cat /proc/interrupts
Linux系統(tǒng)中斷處理
由于中斷會(huì)打斷內(nèi)核中進(jìn)程的正常調(diào)度運(yùn)行,所以要求中斷服務(wù)程序盡可能的短小精悍;但是在實(shí)際系統(tǒng)中,當(dāng)中斷到來(lái)時(shí),要完成工作往往需要進(jìn)行大量的耗時(shí)處理。因此期望讓中斷處理程序運(yùn)行得快,并想讓它完成的工作量多,這兩個(gè)目標(biāo)相互制約,誕生頂/底半部機(jī)制。
中斷上半部分:
中斷處理程序是頂半部——接受中斷,它就立即開(kāi)始執(zhí)行,但只有做嚴(yán)格時(shí)限的工作。能夠被允許稍后完成的工作會(huì)推遲到底半部去,此后,在合適的時(shí)機(jī),底半部會(huì)被開(kāi)終端執(zhí)行。頂半部簡(jiǎn)單快速,執(zhí)行時(shí)禁止部分或者全部中斷。
中斷下半部分:
底半部稍后執(zhí)行,而且執(zhí)行期間可以響應(yīng)所有的中斷。這種設(shè)計(jì)可以使系統(tǒng)處于中斷屏蔽狀態(tài)的時(shí)間盡可能的短,以此來(lái)提高系統(tǒng)的響應(yīng)能力。頂半部只有中斷處理程序機(jī)制,而底半部的實(shí)現(xiàn)有軟中斷,tasklet和工作隊(duì)列等實(shí)現(xiàn)方式;
軟中斷
軟中斷作為下半部機(jī)制的代表,是隨著SMP(share memory processor)的出現(xiàn)應(yīng)運(yùn)而生的,它也是tasklet實(shí)現(xiàn)的基礎(chǔ)(tasklet實(shí)際上只是在軟中斷的基礎(chǔ)上添加了一定的機(jī)制)。軟中斷一般是“可延遲函數(shù)”的總稱,有時(shí)候也包括了tasklet(請(qǐng)讀者在遇到的時(shí)候根據(jù)上下文推斷是否包含tasklet)。它的出現(xiàn)就是因?yàn)橐獫M足上面所提出的上半部和下半部的區(qū)別,使得對(duì)時(shí)間不敏感的任務(wù)延后執(zhí)行,而且可以在多個(gè)CPU上并行執(zhí)行,使得總的系統(tǒng)效率可以更高。它的特性包括:產(chǎn)生后并不是馬上可以執(zhí)行,必須要等待內(nèi)核的調(diào)度才能執(zhí)行。軟中斷不能被自己打斷(即單個(gè)cpu上軟中斷不能嵌套執(zhí)行),只能被硬件中斷打斷(上半部), 可以并發(fā)運(yùn)行在多個(gè)CPU上(即使同一類型的也可以)。所以軟中斷必須設(shè)計(jì)為可重入的函數(shù)(允許多個(gè)CPU同時(shí)操作),因此也需要使用自旋鎖來(lái)保護(hù)其數(shù)據(jù)結(jié)構(gòu)。
軟中斷的調(diào)度時(shí)機(jī):
do_irq完成I/O中斷時(shí)調(diào)用irq_exit。
系統(tǒng)使用I/O APIC,在處理完本地時(shí)鐘中斷時(shí)。
local_bh_enable,即開(kāi)啟本地軟中斷時(shí)。
SMP系統(tǒng)中,cpu處理完被CALL_FUNCTION_VECTOR處理器間中斷所觸發(fā)的函數(shù)時(shí)。
ksoftirqd/n線程被喚醒時(shí)。
軟中斷內(nèi)核線程
在 Linux 中,中斷具有最高的優(yōu)先級(jí)。不論在任何時(shí)刻,只要產(chǎn)生中斷事件,內(nèi)核將立即執(zhí)行相應(yīng)的中斷處理程序,等到所有掛起的中斷和軟中斷處理完畢后才能執(zhí)行正常的任務(wù),因此有可能造成實(shí)時(shí)任務(wù)得不到及時(shí)的處理。中斷線程化之后,中斷將作為內(nèi)核線程運(yùn)行而且被賦予不同的實(shí)時(shí)優(yōu)先級(jí),實(shí)時(shí)任務(wù)可以有比中斷線程更高的優(yōu)先級(jí)。這樣,具有最高優(yōu)先級(jí)的實(shí)時(shí)任務(wù)就能得到優(yōu)先處理,即使在嚴(yán)重負(fù)載下仍有實(shí)時(shí)性保證。但是,并不是所有的中斷都可以被線程化,比如時(shí)鐘中斷,主要用來(lái)維護(hù)系統(tǒng)時(shí)間以及定時(shí)器等,其中定時(shí)器是操作系統(tǒng)的脈搏,一旦被線程化,就有可能被掛起,后果將不堪設(shè)想,所以不應(yīng)當(dāng)被線程化。
軟中斷優(yōu)先在 irq_exit() 中執(zhí)行,如果超過(guò)時(shí)間等條件轉(zhuǎn)為 softirqd 線程中執(zhí)行。滿足以下任一條件軟中斷在 softirqd 線程中執(zhí)行:
在 irq_exit()-》__do_softirq() 中運(yùn)行,時(shí)間超過(guò) 2ms。
在 irq_exit()-》__do_softirq() 中運(yùn)行,輪詢軟中斷超過(guò) 10 次。
在 irq_exit()-》__do_softirq() 中運(yùn)行,本線程需要被調(diào)度。
注:調(diào)用 raise_softirq() 喚醒軟中斷時(shí),不在中斷環(huán)境中。
TASKLET
由于軟中斷必須使用可重入函數(shù),這就導(dǎo)致設(shè)計(jì)上的復(fù)雜度變高,作為設(shè)備驅(qū)動(dòng)程序的開(kāi)發(fā)者來(lái)說(shuō),增加了負(fù)擔(dān)。而如果某種應(yīng)用并不需要在多個(gè)CPU上并行執(zhí)行,那么軟中斷其實(shí)是沒(méi)有必要的。因此誕生了彌補(bǔ)以上兩個(gè)要求的tasklet。它具有以下特性:
a)一種特定類型的tasklet只能運(yùn)行在一個(gè)CPU上,不能并行,只能串行執(zhí)行。
b)多個(gè)不同類型的tasklet可以并行在多個(gè)CPU上。
c)軟中斷是靜態(tài)分配的,在內(nèi)核編譯好之后,就不能改變。但tasklet就靈活許多,可以在運(yùn)行時(shí)改變(比如添加模塊時(shí))。
tasklet是在兩種軟中斷類型的基礎(chǔ)上實(shí)現(xiàn)的,因此如果不需要軟中斷的并行特性,tasklet就是最好的選擇。也就是說(shuō)tasklet是軟中斷的一種特殊用法,即延遲情況下的串行執(zhí)行。
tasklet有兩種,tasklet 和 hi-tasklet:
前者對(duì)應(yīng)softirq_vec[TASKLET_SOFTIRQ];
后者對(duì)應(yīng)softirq_vec[HI_SOFTIRQ]。只是后者排在softirq_vec[]的第一個(gè),所以更早被執(zhí)行;
/proc/softirqs 提供了軟中斷的運(yùn)行情況
# cat /proc/softirqs CPU0 HI: 1 //高優(yōu)先級(jí)TASKLET軟中斷 TIMER: 12571001 //定時(shí)器軟中斷 NET_TX: 826165 //網(wǎng)卡發(fā)送軟中斷 NET_RX: 6263015 //網(wǎng)卡接收軟中斷 BLOCK: 1403226 //塊設(shè)備處理軟中斷 BLOCK_IOPOLL: 0 //塊設(shè)備處理軟中斷 TASKLET: 3752 //普通TASKLET軟中斷 SCHED: 0 //調(diào)度軟中斷 HRTIMER: 0 //當(dāng)前已經(jīng)沒(méi)有使用 RCU: 9729155 //RCU處理軟中斷,主要是callback函數(shù)處理
工作隊(duì)列
工作隊(duì)列(work queue)是Linux kernel中將工作推后執(zhí)行的一種機(jī)制。軟中斷運(yùn)行在中斷上下文中,因此不能阻塞和睡眠,而tasklet使用軟中斷實(shí)現(xiàn),當(dāng)然也不能阻塞和睡眠,工作隊(duì)列可以把工作推后,交由一個(gè)內(nèi)核線程去執(zhí)行—這個(gè)下半部分總是會(huì)在進(jìn)程上下文執(zhí)行,因此工作隊(duì)列的優(yōu)勢(shì)就在于它允許重新調(diào)度甚至睡眠。
workqueue 中幾個(gè)角色關(guān)系:
work :工作/任務(wù)。
workqueue :工作的集合。workqueue 和 work 是一對(duì)多的關(guān)系。
worker :工人。在代碼中 worker 對(duì)應(yīng)一個(gè)work_thread() 內(nèi)核線程。
worker_pool:工人的集合。worker_pool 和 worker 是一對(duì)多的關(guān)系。
pwq(pool_workqueue):中間人 / 中介,負(fù)責(zé)建立起 workqueue 和 worker_pool 之間的關(guān)系。workqueue 和 pwq 是一對(duì)多的關(guān)系,pwq 和 worker_pool 是一對(duì)一的關(guān)系。
通常,在工作隊(duì)列和軟中斷/tasklet中作出選擇,可使用以下規(guī)則:
如果推后執(zhí)行的任務(wù)需要睡眠,那么只能選擇工作隊(duì)列。
如果推后執(zhí)行的任務(wù)需要延時(shí)指定的時(shí)間再觸發(fā),那么使用工作隊(duì)列,因?yàn)槠淇梢岳胻imer延時(shí)(內(nèi)核定時(shí)器實(shí)現(xiàn))。
如果推后執(zhí)行的任務(wù)需要在一個(gè)tick之內(nèi)處理,則使用軟中斷或tasklet,因?yàn)槠淇梢該屨计胀ㄟM(jìn)程和內(nèi)核線程,同時(shí)不可睡眠。
如果推后執(zhí)行的任務(wù)對(duì)延遲的時(shí)間沒(méi)有任何要求,則使用工作隊(duì)列,此時(shí)通常為無(wú)關(guān)緊要的任務(wù)。
實(shí)際上,工作隊(duì)列的本質(zhì)就是將工作交給內(nèi)核線程處理,因此其可以用內(nèi)核線程替換。但是內(nèi)核線程的創(chuàng)建和銷毀對(duì)編程者的要求較高,而工作隊(duì)列實(shí)現(xiàn)了內(nèi)核線程的封裝,不易出錯(cuò),推薦使用工作隊(duì)列。
中斷上下文
中斷代碼運(yùn)行于內(nèi)核空間,中斷上下文即運(yùn)行中斷代碼所需要CPU上下文環(huán)境,需要硬件傳遞過(guò)來(lái)的這些參數(shù),內(nèi)核需要保存的一些其他環(huán)境(主要是當(dāng)前被打斷執(zhí)行的進(jìn)程或其他中斷環(huán)境),這些一般都保存在中斷棧中(x86是獨(dú)立的,其他可能和內(nèi)核棧共享,這和具體處理架構(gòu)密切相關(guān)),在中斷結(jié)束后,進(jìn)程仍然可以從原來(lái)的狀態(tài)恢復(fù)運(yùn)行。
是否處于中斷中,在Linux中是通過(guò)preempt_count來(lái)判斷的,具體如下:
#define in_irq() (hardirq_count()) //在處理硬中斷中
#define in_softirq() (softirq_count()) //在處理軟中斷中
#define in_interrupt() (irq_count()) //在處理硬中斷或軟中斷中
#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0) //包含以上所有情況
總結(jié)和注意的點(diǎn):
1.Linux kernel的設(shè)計(jì)者制定了規(guī)則:
中斷上下文不是調(diào)度實(shí)體,task才是【進(jìn)程(主線程)或者線程】;
優(yōu)先級(jí)順序:硬中斷上下文 》 軟中斷上下文 》 進(jìn)程上下文 ;
中斷上下文(hardirq和softirq context)并不參與調(diào)度(暫不考慮中斷線程化),它們是異步事件的處理機(jī)制,目標(biāo)就是盡快完成處理,返回現(xiàn)場(chǎng)。因此,所有中斷上下文的優(yōu)先級(jí)都是高于進(jìn)程上下文的。也就是說(shuō),對(duì)于用戶進(jìn)程(無(wú)論內(nèi)核態(tài)還是用戶態(tài))或者內(nèi)核線程,除非disable了CPU的本地中斷,否則一旦中斷發(fā)生,它們是沒(méi)有任何能力阻擋中斷上下文搶占當(dāng)前進(jìn)程上下文的執(zhí)行的。
2.Linux 將中斷處理過(guò)程分成了兩個(gè)階段,也就是上半部和下半部:
上半部用來(lái)快速處理中斷,它在中斷禁止模式下運(yùn)行,主要處理跟硬件緊密相關(guān)的或時(shí)間敏感的工作,需要快速執(zhí)行;
下半部用來(lái)延遲處理上半部未完成的工作,通常以軟中斷方式運(yùn)行,可以延遲執(zhí)行。
3. 硬中斷和軟中斷(只要是中斷上下文)執(zhí)行的時(shí)候都不允許內(nèi)核搶占(本文后續(xù)章節(jié)會(huì)講內(nèi)核搶占)。因?yàn)樵谥袛嗌舷挛闹?,唯一能打斷?dāng)前中斷handler的只有更高優(yōu)先級(jí)的中斷,它不會(huì)被進(jìn)程打斷(這點(diǎn)對(duì)于softirq,tasklet也一樣,因此這些bottom half也不能睡眠);如果在中斷上下文中睡眠,則沒(méi)有辦法喚醒它,因?yàn)樗械膚ake_up_xxx都是針對(duì)某個(gè)進(jìn)程而言的,而在中斷上下文中,沒(méi)有進(jìn)程的概念,沒(méi)有相應(yīng)task_struct(這點(diǎn)對(duì)于softirq和tasklet一樣),因此真的睡眠了,比如調(diào)用了會(huì)導(dǎo)致阻塞的例程,內(nèi)核幾乎會(huì)掛。
4.硬中斷可以被另一個(gè)優(yōu)先級(jí)比自己高的硬中斷“中斷”,不能被同級(jí)(同一種硬中斷)或低級(jí)的硬中斷“中斷”,更不能被軟中斷“中斷”。軟中斷可以被硬中斷“中斷”,但是不會(huì)被另一個(gè)軟中斷“中斷”。在一個(gè)CPU上,軟中斷總是串行執(zhí)行。所以在單處理器上,對(duì)軟中斷的數(shù)據(jù)結(jié)構(gòu)進(jìn)行訪問(wèn)不需要加任何同步原語(yǔ)。
5.關(guān)中斷不會(huì)丟失中斷,但是對(duì)于期間到來(lái)的多個(gè)相同的中斷會(huì)合并成一個(gè),即只處理一次;時(shí)鐘中斷中需要更新jieffis計(jì)數(shù)值,如果多個(gè)中斷合成一個(gè),為了減少影響jieffis值準(zhǔn)確性,需要其他硬件時(shí)鐘來(lái)矯正。
本期結(jié)束,我們下期再見(jiàn)??!
原文標(biāo)題:Linux 調(diào)度系統(tǒng)全景指南(上篇)
文章出處:【微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
責(zé)任編輯:haq
-
Linux
+關(guān)注
關(guān)注
87文章
11509瀏覽量
213677
原文標(biāo)題:Linux 調(diào)度系統(tǒng)全景指南(上篇)
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
鴻道Intewell操作系統(tǒng)的Linux實(shí)時(shí)拓展方案

國(guó)產(chǎn)銀河麒麟操作系統(tǒng)V10和星光麒麟V1.0操作系統(tǒng)如何選擇?

云服務(wù)器選擇什么操作系統(tǒng)好?
deepin操作系統(tǒng)介紹

如何在windows上emulate不同操作系統(tǒng)
國(guó)產(chǎn)實(shí)時(shí)操作系統(tǒng):和RT-Linux,Zephyr的實(shí)時(shí)性對(duì)比

linux是實(shí)時(shí)系統(tǒng)還是分時(shí)操作系統(tǒng)
嵌入式 Linux 操作系統(tǒng)配置
linux操作系統(tǒng)安裝步驟 linux操作系統(tǒng)的特點(diǎn)及組成
使用CSL來(lái)補(bǔ)充操作系統(tǒng)調(diào)度程序處理級(jí)聯(lián)中斷

面向功能安全應(yīng)用的汽車開(kāi)源操作系統(tǒng)解決方案

Linux操作系統(tǒng)份額創(chuàng)歷史新高,逼近4.5%里程碑
Linux操作系統(tǒng)運(yùn)行參數(shù)自動(dòng)調(diào)整技術(shù)

深入探討Linux的進(jìn)程調(diào)度器

操作系統(tǒng)的內(nèi)存布局介紹

評(píng)論