作者:新浪微博(@NP等不等于P) 計算機學習微信公眾號(jsj_xx) 信號就是軟件中斷,和硬件中斷有很多類似之處。本文分享我們對信號這種異步事件處理的理解,僅考慮進程,不涉及多線程(如有錯誤,還請指正,謝謝)。 【參考linux kernel source code 4.0,syscall rt_sigaction()、send_signal()、do_signal()】 1 不可靠信號 由于信號歷史悠久,我們還得從不可靠信號講起。 不可靠的根因在于存在競態(tài)時間窗口,畢竟異步就難以預(yù)測發(fā)生信號的時機。早期信號的問題有:
對于pause問題,setjmp是一個治標不治本的解決方案。因為它的暴力跳轉(zhuǎn)會讓其它的信號處理夭折,并且還不能解決好信號掩碼的在遷移時的保護和恢復(fù)。 可見,這些競態(tài)窗口的存在,就是早期信號不可靠的根因??煽啃盘柕囊粋€目的,就是要消滅掉這些競態(tài)窗口。 2 可靠信號 我們(計算機學習微信公眾號:jsj_xx)的理解是:sigprocmask/sigpending/sigsetjmp/siglongjmp/sigsuspend,這些函數(shù)存在的意義就是要解決上文中提到的競態(tài)窗口問題的! 我們逐個分析:
可見,對于等待一個全局變量(全局變量在一個信號處理中設(shè)置)這樣一個處理,總算有了完美方案:sigsuspend。結(jié)合sigaction函數(shù),我們是這么理解的:
這樣,內(nèi)外結(jié)合,自然擁有完全的可靠性。 3 兼容方案 基于sigaction函數(shù),其中也支持對早期不可靠信號的支持:
可見,調(diào)用sigaction時指定SA_RESETHAND(參考代碼,同SA_ONESHOT)和SA_NODEFER(參考代碼,同SA_NOMASK)就可以完美實現(xiàn)早期的信號方式了。關(guān)于重啟系統(tǒng)調(diào)用,注意SIGALRM的處理:一定不能設(shè)置為SA_RESTART方式,或者更苛刻(安全)的,需要設(shè)置為SA_INTERRUPT方式。 4 信號可重入 早期的信號處理中重置默認處理的行為,可以看作是在變通解決重入問題(當然,現(xiàn)在已經(jīng)通過自動掩碼使得同一信號處理不可重入了)。信號處理里要保證調(diào)用異步信號安全的函數(shù)。這是顯然的,畢竟信號是異步處理。需要注意的是,多線程里即使信號處理中使用異步信號安全的函數(shù),也還是需要保存和恢復(fù)errno的。 異步信號不安全函數(shù)的原因有:
信號處理中是不能使用這些不安全的函數(shù)的,否則后果很嚴重。觸類旁通,想想fork()之后、exec()之前,子進程在這段時間里,就只能調(diào)用異步信號安全函數(shù),這是一個道理的。 5 針對同一信號處理時再次發(fā)生的計數(shù) 傳統(tǒng)信號(編號從1到31)是不計次數(shù)的,只計是否發(fā)生過。實時信號(編號從32到64)是記錄次數(shù)的,當然是有上限的(通過ulimit查看)。 需要注意,計數(shù)區(qū)別不能成為評判信號可不可靠的標準,想想硬件中斷的處理就明白了。 6 總結(jié) 可靠信號要解決的問題,無非是(早期信號的)異步處理伴隨的競態(tài)窗口問題,可以說是通過sigprocmask和sigaction聯(lián)合解決了。最后要說的是,信號本質(zhì)就是軟件中斷,因為確實形神兼?zhèn)溆布袛?。?!?/span> 新浪微博(@NP等不等于P) 計算機學習微信公眾號(jsj_xx) 原創(chuàng)技術(shù)文章,感悟計算機,透徹理解計算機! |
|