0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

linux內(nèi)核信號是如何處理的?看完全懂了……

電子設(shè)計 ? 來源:互聯(lián)網(wǎng) ? 作者:佚名 ? 2017-11-16 05:11 ? 次閱讀

本文簡單介紹下Linux信號處理機(jī)制,為介紹二進(jìn)制翻譯下信號處理機(jī)制做一個鋪墊。
本文主要參考書目《Linux內(nèi)核源代碼情景分析》《獨(dú)辟蹊徑品內(nèi)核:Linux內(nèi)核源代碼導(dǎo)讀》
首先,先說一下什么是信號。信號本質(zhì)上是在軟件層次上對中斷機(jī)制的一種模擬,其主要有以下幾種來源:

程序錯誤:除零,非法內(nèi)存訪問…

外部信號:終端Ctrl-C產(chǎn)生SGINT信號,定時器到期產(chǎn)生SIGALRM…

顯式請求:kill函數(shù)允許進(jìn)程發(fā)送任何信號給其他進(jìn)程或進(jìn)程組。

在Linux下,可以通過以下命令查看系統(tǒng)所有的信號:

kill-l

可以通過類似下面的命令顯式的給一個進(jìn)程發(fā)送一個信號:

kill-2pid

上面的命令將2號信號發(fā)送給進(jìn)程id為pid的進(jìn)程。不存在編號為0的信號。

目前Linux支持64種信號。信號分為非實(shí)時信號(不可靠信號)和實(shí)時信號(可靠信號)兩種類型,對應(yīng)于 Linux 的信號值為 1-31 和 34-64。信號是異步的,一個進(jìn)程不必通過任何操作來等待信號的到達(dá),事實(shí)上,進(jìn)程也不知道信號到底什么時候到達(dá)。本文著重于Linux的信號處理機(jī)制,對信號更多的介紹可以參考這里。

一般情況下一個進(jìn)程接受到信號后,會有如下的行為:

進(jìn)程對信號的響應(yīng)

忽略信號:大部分信號可被忽略,除SIGSTOP和SIGKILL信號外(這是超級用戶殺掉或停掉任意進(jìn)程的手段)。

捕獲信號:注冊信號處理函數(shù),它對產(chǎn)生的特定信號做處理。

讓信號默認(rèn)動作起作用:unix內(nèi)核定義的默認(rèn)動作,有5種情況:

a) 流產(chǎn)abort:終止進(jìn)程并產(chǎn)生core文件。

b) 終止stop:終止進(jìn)程但不生成core文件。

c) 忽略:忽略信號。

d) 掛起suspend:掛起進(jìn)程。

e) 繼續(xù)continue:若進(jìn)程是掛起的,則resume進(jìn)程,否則忽略此信號。

注冊信號處理函數(shù)

如果想要進(jìn)程捕獲某個信號,然后作出相應(yīng)的處理,就需要注冊信號處理函數(shù)。同中斷類似,內(nèi)核也為每個進(jìn)程準(zhǔn)備了一個信號向量表,信號向量表中記錄著每個信號所對應(yīng)的處理機(jī)制,默認(rèn)情況下是調(diào)用默認(rèn)處理機(jī)制。當(dāng)進(jìn)程為某個信號注冊了信號處理程序后,發(fā)生該信號時,內(nèi)核就會調(diào)用注冊的函數(shù)。

注冊信號處理函數(shù)是通過系統(tǒng)調(diào)用signal()、sigaction()。其中signal()在可靠信號系統(tǒng)調(diào)用的基礎(chǔ)上實(shí)現(xiàn), 是庫函數(shù)。它只有兩個參數(shù),不支持信號傳遞信息,主要是用于前32種非實(shí)時信號的安裝;而sigaction()是較新的函數(shù)(由兩個系統(tǒng)調(diào)用實(shí) 現(xiàn):sys_signal以及sys_rt_sigaction),有三個參數(shù),支持信號傳遞信息,主要用來與 sigqueue() 系統(tǒng)調(diào)用配合使用,當(dāng)然,sigaction()同樣支持非實(shí)時信號的安裝。sigaction()優(yōu)于signal()主要體現(xiàn)在支持信號帶有參數(shù)。關(guān)于這方面的內(nèi)容,如果想獲取更多,也可參考這里。

Linux下信號處理機(jī)制

進(jìn)程如何發(fā)現(xiàn)和接受信號?

我們知道,信號是異步的,一個進(jìn)程不可能等待信號的到來,也不知道信號會到來,那么,進(jìn)程是如何發(fā)現(xiàn)和接受信號呢?實(shí)際上,信號的接收不是由用戶進(jìn)程來完成的,而是由內(nèi)核代理。當(dāng)一個進(jìn)程P2向另一個進(jìn)程P1發(fā)送信號后,內(nèi)核接受到信號,并將其放在P1的信號隊(duì)列當(dāng)中。當(dāng)P1再次陷入內(nèi)核態(tài)時,會檢查信號隊(duì)列,并根據(jù)相應(yīng)的信號調(diào)取相應(yīng)的信號處理函數(shù)。如下圖所示:


其中,動作c:發(fā)現(xiàn)和捕捉信號

信號檢測和響應(yīng)時機(jī)

剛才我們說,當(dāng)P1再次陷入內(nèi)核時,會檢查信號隊(duì)列。那么,P1什么時候會再次陷入內(nèi)核呢?陷入內(nèi)核后在什么時機(jī)會檢測信號隊(duì)列呢?

當(dāng)前進(jìn)程由于系統(tǒng)調(diào)用、中斷或異常而進(jìn)入系統(tǒng)空間以后,從系統(tǒng)空間返回到用戶空間的前夕。

當(dāng)前進(jìn)程在內(nèi)核中進(jìn)入睡眠以后剛被喚醒的時候(必定是在系統(tǒng)調(diào)用中),或者由于不可忽略信號的存在而提前返回到用戶空間。

進(jìn)入信號處理函數(shù)

發(fā)現(xiàn)信號后,根據(jù)信號向量,知道了處理函數(shù),那么該如何進(jìn)入信號處理程序,又該如何返回呢?

我們知道,用戶進(jìn)程提供的信號處理函數(shù)是在用戶態(tài)里的,而我們發(fā)現(xiàn)信號,找到信號處理函數(shù)的時刻處于內(nèi)核態(tài)中,所以我們需要從內(nèi)核態(tài)跑到用戶態(tài)去執(zhí)行信號處理程序,執(zhí)行完畢后還要返回內(nèi)核態(tài)。這個過程如下圖所示:

如圖中所見,處理信號的整個過程是這樣的:進(jìn)程由于 系統(tǒng)調(diào)用或者中斷 進(jìn)入內(nèi)核,完成相應(yīng)任務(wù)返回用戶空間的前夕,檢查信號隊(duì)列,如果有信號,則根據(jù)信號向量表找到信號處理函數(shù),設(shè)置好“frame”后,跳到用戶態(tài)執(zhí)行信號處理函數(shù)。信號處理函數(shù)執(zhí)行完畢后,返回內(nèi)核態(tài),設(shè)置“frame”,再返回到用戶態(tài)繼續(xù)執(zhí)行程序。

在上面這段話中,我提到“frame”,frame是什么?那么為什么要設(shè)置frame?為什么在執(zhí)行完信號處理函數(shù)后還要返回內(nèi)核態(tài)呢?

什么叫Frame?

在調(diào)用一個子程序時,堆棧要往下(邏輯意義上是往上)伸展,這是因?yàn)樾枰诙褩V斜4孀映绦虻姆祷氐刂罚€因?yàn)樽映绦蛲芯植孔兞?,也要占用堆棧中的空間。此外,調(diào)用子程序時的參數(shù)也是在堆棧中。子程序調(diào)用嵌套越深,則堆棧伸展的層次也越多。在堆棧中的每一個這樣的層次,就稱為一個”框架”,即frame。

一般來說,當(dāng)子程序和調(diào)用它的程序在同一空間中時,堆棧的伸展,也就是堆棧中框架的建立,過程主要如下:

call指令將返回地址壓入堆棧(自動)

用push指令壓入調(diào)用參數(shù)

調(diào)整堆棧指針來分配局部變量

為什么以及怎么設(shè)置frame?

我們知道,當(dāng)進(jìn)程陷入內(nèi)核態(tài)的時候,會在堆棧中保存中斷現(xiàn)場。因?yàn)橛脩魬B(tài)和內(nèi)核態(tài)是兩個運(yùn)行級別,所以要使用兩個不同的棧。當(dāng)用戶進(jìn)程通過系統(tǒng)調(diào)用剛進(jìn)入內(nèi)核的時候,CPU會自動在該進(jìn)程的內(nèi)核棧上壓入下圖所示的內(nèi)容:(圖來自《Linux內(nèi)核完全注釋》)

在處理完系統(tǒng)調(diào)用以后,就要調(diào)用do_signal()函數(shù)進(jìn)行設(shè)置frame等工作。這時內(nèi)核堆棧的狀態(tài)應(yīng)該跟下圖左半部分類似(系統(tǒng)調(diào)用將一些信息壓入棧了):

在找到了信號處理函數(shù)之后,do_signal函數(shù)首先把內(nèi)核堆棧中存放返回執(zhí)行點(diǎn)的eip保存為old_eip,然后將eip替換為信號處理函數(shù)的地址,然后將內(nèi)核中保存的“原ESP”(即用戶態(tài)棧地址)減去一定的值,目的是擴(kuò)大用戶態(tài)的棧,然后將內(nèi)核棧上的內(nèi)容保存到用戶棧上,這個過程就是設(shè)置frame.值得注意的是下面兩點(diǎn):

之所以把EIP的值設(shè)置成信號處理函數(shù)的地址,是因?yàn)橐坏┻M(jìn)程返回用戶態(tài),就要去執(zhí)行信號處理程序,所以EIP要指向信號處理程序而不是原來應(yīng)該執(zhí)行的地址。

之所以要把frame從內(nèi)核棧拷貝到用戶棧,是因?yàn)檫M(jìn)程從內(nèi)核態(tài)返回用戶態(tài)會清理這次調(diào)用所用到的內(nèi)核棧(類似函數(shù)調(diào)用),內(nèi)核棧又太小,不能單純的在棧上保存另一個frame(想象一下嵌套信號處理),而我們需要EAX(系統(tǒng)調(diào)用返回值)、EIP這些信息以便執(zhí)行完信號處理函數(shù)后能繼續(xù)執(zhí)行程序,所以把它們拷貝到用戶態(tài)棧以保存起來。

以上這些搞清楚之后,下面的事情就順利多了。這時進(jìn)程返回用戶空間,就會根據(jù)內(nèi)核棧中的EIP值執(zhí)行信號處理函數(shù)。那么,信號處理程序執(zhí)行完后,怎么返回程序繼續(xù)執(zhí)行呢?

信號處理函數(shù)執(zhí)行完后怎么辦?

信號處理程序執(zhí)行完畢之后,進(jìn)程會主動調(diào)用sigreturn()系統(tǒng)調(diào)用再次回到內(nèi)核,查看有沒有其他信號需要處理,如果沒有,這時內(nèi)核就會做一些善后工作,將之前保存的frame恢復(fù)到內(nèi)核棧,恢復(fù)eip的值為old_eip,然后返回用戶空間,程序就能夠繼續(xù)執(zhí)行。至此,內(nèi)核遍完成了一次(或幾次)信號處理工作。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11123

    瀏覽量

    207895
  • 數(shù)字信號處理
    +關(guān)注

    關(guān)注

    15

    文章

    539

    瀏覽量

    45690
  • IP內(nèi)核
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    12784
收藏 人收藏

    評論

    相關(guān)推薦

    linux驅(qū)動程序如何加載進(jìn)內(nèi)核

    Linux系統(tǒng)中,驅(qū)動程序是內(nèi)核與硬件設(shè)備之間的橋梁。它們允許內(nèi)核與硬件設(shè)備進(jìn)行通信,從而實(shí)現(xiàn)對硬件設(shè)備的控制和管理。 驅(qū)動程序的編寫 驅(qū)動程序的編寫是Linux驅(qū)動開發(fā)的基礎(chǔ)。在編
    的頭像 發(fā)表于 08-30 15:02 ?189次閱讀

    Linux內(nèi)核測試技術(shù)

    Linux 內(nèi)核Linux操作系統(tǒng)的核心部分,負(fù)責(zé)管理硬件資源和提供系統(tǒng)調(diào)用接口。隨著 Linux 內(nèi)核的不斷發(fā)展和更新,其復(fù)雜性和代碼規(guī)
    的頭像 發(fā)表于 08-13 13:42 ?246次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>測試技術(shù)

    Linux內(nèi)核信號的傳遞過程

    前面我們已經(jīng)介紹了內(nèi)核注意到信號的到來,調(diào)用相關(guān)函數(shù)更新進(jìn)程描述符以便進(jìn)程接收處理信號。但是,如果目標(biāo)進(jìn)程此時沒有運(yùn)行,內(nèi)核則推遲傳遞
    的頭像 發(fā)表于 01-17 09:51 ?869次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>中<b class='flag-5'>信號</b>的傳遞過程

    一文詳解Linux內(nèi)核-信號的產(chǎn)生過程

    許多內(nèi)核函數(shù)產(chǎn)生信號:它們完成信號處理的第一階段,也就是更新一個或多個進(jìn)程描述符。
    的頭像 發(fā)表于 01-13 13:48 ?1019次閱讀

    Linux內(nèi)核信號詳解

    5.18.18的定義 4.2.4 ARM/linux5.18.18的定義 4.2.5 RISC-V/linux6.7 4.1 信號描述符和信號處理
    的頭像 發(fā)表于 01-13 09:40 ?1209次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>中<b class='flag-5'>信號</b>詳解

    rk3399移植Linux內(nèi)核

    RK3399是一款由中國廠商瑞芯微推出的高性能處理器芯片,被廣泛用于嵌入式系統(tǒng)開發(fā)。在進(jìn)行應(yīng)用程序開發(fā)之前,我們需要將Linux內(nèi)核移植到RK3399上,以支持硬件的驅(qū)動和功能。本文將詳細(xì)介紹如何將
    的頭像 發(fā)表于 01-08 09:56 ?799次閱讀

    示波器如何處理有噪聲的信號

    示波器如何處理有噪聲的信號? 示波器是一種用于測量和顯示電信號的設(shè)備,可以幫助工程師和科學(xué)家分析和診斷電路故障。然而,在實(shí)際的測量中,信號往往會受到各種噪聲的干擾,這可能會導(dǎo)致測量結(jié)果
    的頭像 發(fā)表于 12-21 15:37 ?859次閱讀

    獲取Linux內(nèi)核源碼的方法

    (ELF1/ELF1S開發(fā)板及顯示屏)Linux內(nèi)核是操作系統(tǒng)中最核心的部分,它負(fù)責(zé)管理計算機(jī)硬件資源,并提供對應(yīng)用程序和其他系統(tǒng)組件的訪問接口,控制著計算機(jī)的內(nèi)存、處理器、設(shè)備驅(qū)動程序和文件系統(tǒng)等
    的頭像 發(fā)表于 12-13 09:49 ?537次閱讀
    獲取<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>源碼的方法

    ADAS1000發(fā)送寄存器后會偶爾出現(xiàn)心電信號完全消失的情況,要如何處理?

    您好, 目前我使用ADAS1000做心電模擬前端,已經(jīng)獲取到心電信號和呼吸信號,但是遇到一個問題,在運(yùn)行過程中,我想發(fā)送命令來更改寄存器配置,來更改ADAS的工作模式,發(fā)現(xiàn)發(fā)送寄存器后會偶爾出現(xiàn)心電信號
    發(fā)表于 12-13 08:26

    AD8302輸入信號何處理?

    在使用AD8302的時候,芯片手冊上描述輸入信號為-60dBm~0dBm在50Ω的系統(tǒng)中,轉(zhuǎn)換過來就是223.61uV~632.46mV的電壓范圍。 請問下,1. 如何控制輸入信號在AD8302的要求范圍內(nèi)呢? 2.當(dāng)信號高于這
    發(fā)表于 12-08 06:06

    何處理MOS管小電流發(fā)熱?

    何處理MOS管小電流發(fā)熱?
    的頭像 發(fā)表于 12-07 15:13 ?492次閱讀
    如<b class='flag-5'>何處理</b>MOS管小電流發(fā)熱?

    什么是串?dāng)_?該如何處理它?

    什么是串?dāng)_?該如何處理它?
    的頭像 發(fā)表于 12-05 16:39 ?669次閱讀
    什么是串?dāng)_?該如<b class='flag-5'>何處理</b>它?

    Linux內(nèi)核UDP收包為什么效率低

    現(xiàn)在很多人都在詬病Linux內(nèi)核協(xié)議棧收包效率低,不管他們是真的懂還是一點(diǎn)都不懂只是聽別人說的,反正就是在一味地懟Linux內(nèi)核協(xié)議棧,他們的武器貌似只有DPDK。 但是,即便
    的頭像 發(fā)表于 11-13 10:38 ?385次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>UDP收包為什么效率低

    請問HC-SR04的回響信號是如何處理?

    HC-SR04模塊中,發(fā)送8個40KHZ的方波后,接受回波信號處理,然后在ECHO中輸出一段與時間成正比的高電平。 我想問下,回波信號何處理?目前在做一個手機(jī)支架,為了省成本,不使
    發(fā)表于 10-26 08:26

    調(diào)試TrustZone時,如何處理HardFault?

    調(diào)試TrustZone時,如何處理HardFault?
    的頭像 發(fā)表于 09-27 16:33 ?536次閱讀
    調(diào)試TrustZone時,如<b class='flag-5'>何處理</b>HardFault?