正規(guī)品牌網(wǎng)站設(shè)計推薦seo網(wǎng)站優(yōu)化多少錢
目錄
信號的處理時機
引入
思考 --?什么時候才能算合適的時候呢?
用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài)
引入
內(nèi)核地址空間?
引入
思考 --?進程為什么能切換成內(nèi)核態(tài)呢?
虛擬地址空間
注意點
原理 (總結(jié)一下)
為什么+如何進入內(nèi)核態(tài)?
引入
介紹
底層原理(int 80)?
cpu的寄存器
用戶級
內(nèi)核級
如何知道進入了內(nèi)核態(tài)
硬件上
軟件上
用戶態(tài)和內(nèi)核態(tài)的來回切換?
為什么
如何切換
信號的處理流程?
介紹
詳細圖解
描述?
默認操作
忽略操作
自定義操作
抽象圖解?
交叉點處
方向
橫線
信號的處理時機
引入
- 之前我們說過,信號被os發(fā)送到進程,實際上是修改了pending信號集
- 然后進程會在合適的時候處理
- 那究竟什么時候才能算合適的時候呢?
思考 --?什么時候才能算合適的時候呢?
- 處理信號必然不是我們做的,而是os,因為信號是內(nèi)核數(shù)據(jù)
- 那么處理信號時,就得處于內(nèi)核的范疇,不然怎么訪問os的數(shù)據(jù)
- 也就是處于內(nèi)核態(tài)
- 那么肯定也會存在用戶態(tài),和內(nèi)核態(tài)對應(yīng),也就存在內(nèi)核態(tài)和用戶態(tài)的切換
- 那么內(nèi)核態(tài)就擁有三種階段 -- 剛進入內(nèi)核態(tài),在內(nèi)核態(tài)執(zhí)行任務(wù)時,準備轉(zhuǎn)為用戶態(tài)時
那么是哪個階段開始處理信號的呢?
- 一般是在執(zhí)行完任務(wù)后,內(nèi)核態(tài)準備轉(zhuǎn)為用戶態(tài)時,會進行信號的處理
- (因為任務(wù)肯定第一位嘛,信號的處理又不急于這一時)
用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài)
引入
- 雖然我們是這樣說的 -- 由內(nèi)核態(tài)轉(zhuǎn)為用戶態(tài)時,就會處理信號
- 但是這個操作我們看不到,怎么知道到底有沒有轉(zhuǎn)換呢?
- 說到底,究竟是怎么轉(zhuǎn)換的呢?未免有點太抽象了
內(nèi)核地址空間?
引入
- 其實并不抽象,所有看起來復(fù)雜的行為都是將[底層一些簡單的操作]封裝而成的
- 比如,可以首先來思考這個問題 -- 進程為什么能切換成內(nèi)核態(tài)呢?
思考 --?進程為什么能切換成內(nèi)核態(tài)呢?
- 內(nèi)核態(tài),也就是可以使用os內(nèi)部的數(shù)據(jù)/接口
那為什么一個進程,它可以有這樣的行為呢?
- 肯定是它此時的權(quán)限修改成了os的權(quán)限
如何使用os內(nèi)部的數(shù)據(jù)/接口呢?
- 要使用這些,必然是和使用普通數(shù)據(jù)/接口一樣,要訪問實際的內(nèi)存的
- 畢竟他們本質(zhì)沒有區(qū)別,只是權(quán)限不一樣
- 而訪問內(nèi)存必須通過虛擬地址空間+頁表+MMU實現(xiàn)
- 我們無法直接操作物理內(nèi)存!!
- 既然可以訪問內(nèi)核數(shù)據(jù),那內(nèi)核肯定也有自己的進程空間+頁表
那到底有沒有呢?
- 有的!
虛擬地址空間
- 之前學(xué)習(xí)的地址空間中本身就有1G的空間,是存放內(nèi)核空間的:?
- 也就是說,我們切換為內(nèi)核態(tài),依賴的是 -- 進程地址空間有內(nèi)核空間
注意點
既然有內(nèi)核空間,自然也有內(nèi)核級的頁表用來映射
但是要注意!!!
每個進程的用戶空間,對應(yīng)的是獨立的內(nèi)存塊
難道每個進程擁有的內(nèi)核空間,它對應(yīng)的內(nèi)存也是獨立的嗎?
- 不會的!
- 內(nèi)核資源是所有進程共用的,不會讓每個進程去瓜分一部分
- [進程的獨立性]要求用戶空間對應(yīng)的內(nèi)存都是獨立的,但每個進程可以使用相同的os資源
- 所以,內(nèi)核級的頁表只需要一份(因為對應(yīng)的物理內(nèi)存是同一塊),它可以被所有進程看到
- 所以,無論進程如何切換,我們看到的都是同一份os資源
原理 (總結(jié)一下)
- 進程可以切換為內(nèi)核態(tài)的原因就在于,每個進程中都有內(nèi)核地址空間
- 只要切換訪問位置和訪問權(quán)限,自然可以通過內(nèi)核地址空間訪問內(nèi)核數(shù)據(jù)嚕
為什么+如何進入內(nèi)核態(tài)?
引入
知道了進程是可以切換的
那么究竟為什么要切換成內(nèi)核態(tài),底層又是如何切換的呢?
介紹
- 當(dāng)我們需要訪問內(nèi)核數(shù)據(jù)時,就需要進入內(nèi)核態(tài)
- 我們大多都是通過系統(tǒng)調(diào)用接口,來使用內(nèi)核數(shù)據(jù)的
- 所以,調(diào)用系統(tǒng)調(diào)用,自動就可以進入內(nèi)核態(tài)(因為之前在使用的時候,并沒有什么特殊行為)
- 并且,我們不用把系統(tǒng)調(diào)用想的那么神秘,他也只是一個函數(shù)而已(只不過非常接近底層)
- 系統(tǒng)調(diào)用和使用庫函數(shù)本質(zhì)上沒有區(qū)別,都是在進程自己的地址空間內(nèi)進行跳轉(zhuǎn)的
?
底層原理(int 80)?
- 在每個系統(tǒng)調(diào)用函數(shù)開始前,都需要先切換成內(nèi)核態(tài)
- 它通過int(interrupt 的縮寫) 80 這個匯編指令,來切換成內(nèi)核態(tài)
- 而匯編的底層是通過cpu的寄存器實現(xiàn)的
cpu的寄存器
實際上存在兩套寄存器,用戶級的和內(nèi)核級的
用戶級
- 實際上,我們將[平時寫的簡單代碼]轉(zhuǎn)換為匯編指令,里面用到的eax等等,就是用戶級的寄存器
內(nèi)核級
- 存放與權(quán)限/控制相關(guān)數(shù)據(jù)的寄存器,我們看不見
- 內(nèi)核級寄存器里面有一個CR3
- 它用來表示當(dāng)前cpu的訪問權(quán)限 -- 內(nèi)核/用戶
- 所以實際上int 80匯編指令,就是通過修改CR3寄存器的數(shù)據(jù),來進入內(nèi)核態(tài)
?
如何知道進入了內(nèi)核態(tài)
硬件上
通過CR3寄存器的數(shù)據(jù)得知的(寄存器是硬件的一部分)
軟件上
- 其實我們已經(jīng)在上面介紹了,只要檢測執(zhí)行的位置是否指向內(nèi)核空間即可
- 指向內(nèi)核空間,就說明此時正在執(zhí)行系統(tǒng)級別的代碼,此時也就處于內(nèi)核態(tài)
?
用戶態(tài)和內(nèi)核態(tài)的來回切換?
為什么
總不能從用戶態(tài)切到內(nèi)核態(tài)后,我們就不切回來了吧
我們肯定還有很多沒有執(zhí)行的用戶級代碼呢
如何切換
- 其實原理我們已經(jīng)都介紹過了
- 只要我們可以拿到進程執(zhí)行相關(guān)的數(shù)據(jù),我們也就可以按照上面的原理 --?跳轉(zhuǎn)地址空間,修改寄存器數(shù)據(jù),來切換狀態(tài)
- (當(dāng)然這里只是一個大概,實際上非常復(fù)雜的)
- 剛好cpu的寄存器里面,就存放著很多進程執(zhí)行相關(guān)的數(shù)據(jù)結(jié)構(gòu)的指針(也就是進程的上下文)
信號的處理流程?
知道了原理后,我們就可以明白,os究竟是如何處理信號的
介紹
詳細圖解
描述?
- 首先我們要先陷入內(nèi)核態(tài)(可能是系統(tǒng)調(diào)用,也可能是異常/中斷導(dǎo)致的)
- 然后在內(nèi)核態(tài)下,os完成一系列的任務(wù)
- 在即將返回用戶態(tài),繼續(xù)向下執(zhí)行代碼前,我們正好處于內(nèi)核態(tài)下,有能力,可以順手處理收到的信號
- 所以,os開始處理信號!
- os先去檢查信號在內(nèi)核中的兩種信號集 -- pending,block
- 如果該信號被阻塞,os可以直接返回到用戶態(tài)
- 但如果滿足條件,我們拿到對應(yīng)信號的處理函數(shù)后
- 這里就要分情況討論了:
默認操作
- 如果需要終止進程,os可以直接進行終止進程的調(diào)度
- 如果該進程中有需要刷新數(shù)據(jù)/dump到外設(shè),os在內(nèi)核態(tài)下可以直接操作,操作完再退出進程
- 如果該進程不退出,也是一樣的:
- eg:有個信號用來暫停進程,也可以在內(nèi)核態(tài)下直接實現(xiàn),直接修改進程狀態(tài),然后調(diào)度下一個進程
忽略操作
- 如果是忽略,os只需要將pending信號集由1改為0,即可返回到用戶態(tài),執(zhí)行下面的代碼嚕
自定義操作
- 如果是自定義的操作,就有點麻煩了
- 因為默認和忽略都可以在內(nèi)核態(tài)下直接完成,因為os的權(quán)限是最大的,什么資源都可以拿到
- 但是在執(zhí)行自定義函數(shù)時,需要轉(zhuǎn)換到用戶態(tài)才行
為什么要轉(zhuǎn)換到用戶態(tài)呢?內(nèi)核態(tài)下不能執(zhí)行嗎?
- 內(nèi)核態(tài)當(dāng)然可以執(zhí)行進程的代碼,它可以拿到所有的資源
- 但是,萬一該函數(shù)中有違規(guī)操作(用戶態(tài)下不可以執(zhí)行的操作)
- 卻沒有被內(nèi)核態(tài)下的進程識別到,就可能會導(dǎo)致不好的后果
- 為了避免這些情況,普通代碼還是讓用戶態(tài)進程執(zhí)行的好
在用戶態(tài)下執(zhí)行完成后,也就該返回內(nèi)核態(tài)了
- 不僅是因為,處理完信號后,需要修改pending位圖
- 也在于,進程需要返回到陷入內(nèi)核態(tài)的執(zhí)行位置,然后繼續(xù)向下執(zhí)行
- 而這些操作都需要訪問os資源
抽象圖解?
將信號處理過程 --?從信號需要從用戶態(tài)陷入到內(nèi)核態(tài) -> 處理完信號,返回原先的執(zhí)行位置?抽象出來,得到該圖:
交叉點處
就是os開始處理信號的時候
方向
圖中的箭頭,就是os執(zhí)行流的變化方向
橫線
- 如果用一條橫線貫穿該圖,那么橫線上方就是用戶態(tài),下方就是內(nèi)核態(tài)
- (可以看到信號處理的時候是在內(nèi)核態(tài)中)
- 橫線與圖的四個交點就可以代表,進程的狀態(tài)變化次數(shù)
- 而交點所在的方向,就代表了狀態(tài)的切換方向