操作系統(tǒng)運(yùn)行中,種有各種事情打斷和切換,通過(guò)系統(tǒng)陷阱來(lái)實(shí)現(xiàn):

簡(jiǎn)單來(lái)說(shuō)就和應(yīng)用層的回調(diào)函數(shù)一樣, 只不過(guò)這些處理是在操作系統(tǒng)內(nèi)核里面,系統(tǒng)初始化時(shí)就填充好了IDT(interrupt dispatch table), 當(dāng)中斷發(fā)生時(shí), 系統(tǒng)會(huì)根據(jù)中斷類型,去調(diào)用對(duì)應(yīng)的ISR(interrupt service routine). 當(dāng)中斷發(fā)生時(shí),操作系統(tǒng)內(nèi)核會(huì)保存足夠多的信息(陷阱幀), 這樣系統(tǒng)處理完中斷之后可以回到原來(lái)的地方繼續(xù)執(zhí)行。看起來(lái)好像和我們應(yīng)用層的函數(shù)調(diào)用一樣, 但是他們的實(shí)現(xiàn)是完全不同的, 函數(shù)調(diào)用是同一線程, 通過(guò)堆棧來(lái)實(shí)現(xiàn)的;中斷處理涉及到線程切換,要保存線程的執(zhí)行環(huán)境。
中斷處理流程圖:

IRQL(interrupt request level) - 中斷請(qǐng)求級(jí)別:

每種中斷都有自己的優(yōu)先級(jí), 高優(yōu)先級(jí)的中斷可以打斷低優(yōu)先級(jí)的中斷的處理, 反之則不行。
對(duì)應(yīng)用層開(kāi)發(fā)人員來(lái)說(shuō),最重要的是最下面的3個(gè)軟件中斷級(jí)別:
(1) DPC/dispatch: 系統(tǒng)的線程調(diào)度器工作在這一級(jí)別, 它可以決定掛起和調(diào)度哪個(gè)線程。DPC(deferred procedure call)主要是給驅(qū)動(dòng)程序用的,每個(gè)處理器都有一個(gè)DPC列表, 處理器在降級(jí)當(dāng)前IRQL之前, 會(huì)先把DPC列表里的事情處理完。
(2) APC: APC即asynchronous procedure call, 每個(gè)線程都有一個(gè)APC隊(duì)列, 我們可以往該隊(duì)列中加入自己要處理的事情(QueueUserAPC), 然后系統(tǒng)會(huì)在當(dāng)該線程進(jìn)入alertable wait state時(shí)調(diào)用我們加入的操作,我們可以通過(guò)SleepEx/WaitForMultipleObjectEx讓該線程進(jìn)入這種等待狀態(tài)。我們常見(jiàn)的OVERLAPPED ReadFileEx/WriteFileEx就是通過(guò)這種方式實(shí)現(xiàn)的。
(3) Passive/Low: 這個(gè)實(shí)際上不是一個(gè)IRQL, 我們普通的用戶代碼就運(yùn)行在這個(gè)級(jí)別,所以它可以隨時(shí)被打斷。
系統(tǒng)服務(wù)調(diào)用:

在Pentium II 之前, 0x2e中斷進(jìn)入系統(tǒng)內(nèi)核(eax傳遞服務(wù)號(hào)), Pentium II 之后處理器提供了Sysenter/Sysexit指令直接進(jìn)出內(nèi)核。
內(nèi)核對(duì)GUI線程和非GUI線程有不同的SSDT(System Services Descriptor Table), GUI線程服務(wù)分發(fā)表更完整,包含了窗口和GDI相關(guān)部分, 在第一調(diào)用user32/GDI相關(guān)的API時(shí)系統(tǒng)會(huì)修改該線程系統(tǒng)服務(wù)表的指針。
內(nèi)核對(duì)象結(jié)構(gòu):

應(yīng)用層打交道的內(nèi)核對(duì)象實(shí)際上是執(zhí)行體對(duì)象, 它是有一個(gè)或多個(gè)真正的內(nèi)核對(duì)象組成的。內(nèi)核對(duì)象由對(duì)象頭和對(duì)象體組成, 對(duì)象頭對(duì)每種對(duì)象包含一致的結(jié)構(gòu), 對(duì)象體則每種對(duì)象各不相同。對(duì)象頭里的對(duì)象類型(object type), 對(duì)同種類型的對(duì)象,指向相同的地址,表明了該種對(duì)象的屬性和方法。對(duì)象管理器通過(guò)對(duì)象頭來(lái)管理內(nèi)核對(duì)象。
內(nèi)核對(duì)象同步原理:

應(yīng)用層我們經(jīng)常調(diào)用WaitForSingle(Multiple)Object, 操作系統(tǒng)內(nèi)部是怎么實(shí)現(xiàn)的?
每個(gè)可同步的對(duì)象, 內(nèi)部都有一個(gè)分發(fā)器頭(dispatch_header), 分發(fā)器頭包含了對(duì)象類型,狀態(tài),以及等待該對(duì)象的線程列表;每個(gè)處于等待狀態(tài)的線程, 都有一個(gè)等待塊列表(wait block list), 每個(gè)等待塊代表一個(gè)等待線程。這樣就很好理解了,當(dāng)我們把一個(gè)同步對(duì)象設(shè)置成有信號(hào)狀態(tài)時(shí), 系統(tǒng)沿著分發(fā)器頭的等待線程列表遍歷,找到可激活的線程,將它轉(zhuǎn)入就緒狀態(tài)參與線程調(diào)度。
Critical Section是如何實(shí)現(xiàn)用戶態(tài)等待的?
我們知道CRITICAL_SECTION是同一進(jìn)程內(nèi)我們最常用的同步機(jī)制, 號(hào)稱不用轉(zhuǎn)入內(nèi)核,以高效聞名, 它是怎么實(shí)現(xiàn)的?
單純?cè)谟脩魬B(tài)等待, 我們只能死循環(huán),不停的檢測(cè), 也就是所謂的自旋鎖(SpinLock), critical section如果用這種方式實(shí)現(xiàn),何來(lái)高效可言。
實(shí)際上critical section的大概實(shí)現(xiàn)是這樣的: 它內(nèi)部包含一個(gè)標(biāo)志位以及一個(gè)event object, 進(jìn)入critical section時(shí)首先嘗試設(shè)置標(biāo)志位,如果設(shè)置成功,表示成功獲得資源;如果標(biāo)志位已經(jīng)被設(shè)置, 則等待event事件。其中標(biāo)志位的設(shè)置是用類似interlockedexchange這樣的原子API操作的。這樣只要沒(méi)有資源競(jìng)爭(zhēng),大部分情況下都能滿足我們的高效需求, 如果有資源競(jìng)爭(zhēng),實(shí)際上還是會(huì)轉(zhuǎn)入內(nèi)核態(tài)掛起線程。
posted on 2016-03-22 22:48
Richard Wei 閱讀(2184)
評(píng)論(1) 編輯 收藏 引用 所屬分類:
windows desktop