linux訊號處理機制的原理

來源:互聯網
上載者:User

訊號處理機制的原理:
    核心給一個進程發送非強制中斷訊號的方法,是在進程所在的進程表項的訊號網域設定對應於該訊號的位。這裡要補充的是,如果訊號發送給一個正在睡眠的進程,那麼要 看該進程進入睡眠的優先順序,如果進程睡眠在可被中斷的優先順序上,則喚醒進程;否則僅設定進程表中訊號域相應的位,而不喚醒進程。這一點比較重要,因為進程 檢查是否收到訊號的時機是:一個進程在即將從核心態返回到使用者態時;或者,在一個進程要進入或離開一個適當的低調度優先順序睡眠狀態時。
    核心處理一個進程收到的訊號的時機是在一個進程從核心態返回使用者態時。所以,當一個進程在核心態下運行時,非強制中斷訊號並不立即起作用,要等到將返回使用者態 時才處理。進程只有處理完訊號才會返回使用者態(上面的例子程式中,在步驟5中,解除阻塞後,先列印caught SIGQUIT,再列印SIGQUIT unblocked,即在sigprocmask返回前,訊號處理常式先執行),進程在使用者態下不會有未處理完的訊號。
    核心處理一個進程收到的非強制中斷訊號是在該進程的上下文中,因此,進程必須處於運行狀態。如果進程收到一個要捕捉的訊號,那麼進程從核心態返回使用者態時執行 使用者定義的函數。而且執行使用者定義的函數的方法很巧妙,核心是在使用者棧上建立一個新的層,該層中將返回地址的值設定成使用者定義的處理函數的地址,這樣進程 從核心返回彈出棧頂時就返回到使用者定義的函數處,從函數返回再彈出棧頂時,才返回原先進入核心的地方,接著原來的地方繼續運行。這樣做的原因是使用者定義的 處理函數不能且不允許在核心態下執行(如果使用者定義的函數在核心態下啟動並執行話,使用者就可以獲得任何許可權)。
    在訊號的處理方法中有幾點特別要引起注意。第一,在一些系統中,當一個進程處理完中斷訊號返回使用者態之前,核心清除使用者區中設定的對該訊號的處理常式的地 址,即下一次進程對該訊號的處理方法又改為預設值,除非在下一次訊號到來之前再次使用signal系統調用。這可能會使得進程在調用signal之前又得 到該訊號而導致退出。在BSD中,核心不再清除該地址。但不清除該地址可能使得進程因為過多過快的得到某個訊號而導致堆疊溢位。為了避免出現上述情況。在 BSD系統中,核心類比了對硬體中斷的處理方法,即在處理某個中斷時,阻止接收新的該類中斷。
    第二個要引起注意的是,如果要捕捉的訊號發生於進程正在一個系統調用中時,並且該進程睡眠在可中斷的優先順序上(若系統調用未睡眠而是在運行,根據上面的分 析,等該系統調用運行完畢後再處理訊號),這時該訊號引起進程作一次longjmp,跳出睡眠狀態,返回使用者態並執行訊號處理常式。當從訊號處理常式返回 時,進程就象從系統調用返回一樣,但返回了一個錯誤如-1,並將errno設定為EINTR,指出該次系統調用曾經被中斷。這要注意的是,BSD系統中內 核可以自動地重新開始系統調用,或者手如上面所述手動設定重啟。
    第三個要注意的地方:若進程睡眠在可中斷的優先順序上,則當它收到一個要忽略的訊號時,該進程被喚醒,但不做longjmp,一般是繼續睡眠。但使用者感覺不 到進程曾經被喚醒,而是象沒有發生過該訊號一樣。所以能夠使pause、sleep等函數從掛起態返回的訊號必須要有訊號處理函數,如果沒有什麼動作,可 以將處理函數設為空白。
    第四個要注意的地方:核心對子進程終止(SIGCLD)訊號的處理方法與其他訊號有所區別。當進程正常或異常終止時,核心都向其父進程發一個SIGCLD 訊號,預設情況下,父進程忽略該訊號,就象沒有收到該訊號似的,如果父進程希望獲得子進程終止的狀態,則應該事先用signal函數為SIGCLD訊號設 置訊號處理常式,在訊號處理常式中調用wait。
    SIGCLD訊號的作用是喚醒一個睡眠在可被中斷優先順序上的進程。如果該進程捕捉了這個訊號,就象普通訊號處理一樣轉到處理常式。如果進程忽略該訊號,則 什麼也不做。其實wait不一定放在訊號處理函數中,但這樣的話因為不知道子進程何時終止,在子進程終止前,wait將使父進程掛起休眠。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

Tags Index: