linux调用信号处理程序后返回,如何在Linux上执行异步信号处理程序?
Source#1(Andries Brouwer)對(duì)于單線程進(jìn)程是正確的 . 源#2(SCO Unix)對(duì)于Linux是錯(cuò)誤的,因?yàn)長(zhǎng)inux不喜歡sigwait中的線程(2) . 關(guān)于第一個(gè)可用的線程,Moshe Bar是正確的 .
Which thread gets the signal? Linux的手冊(cè)頁(yè)是一個(gè)很好的參考 . 進(jìn)程使用帶有CLONE_THREAD的clone(2)來(lái)創(chuàng)建多個(gè)線程 . 這些線程屬于"thread group"并共享一個(gè)進(jìn)程ID . 克隆手冊(cè)(2)說(shuō),
可以使用kill(2)將信號(hào)作為整體(即,TGID)發(fā)送到線程組,或者使用tgkill(2)發(fā)送到特定線程(即,TID) . 信號(hào)處理和操作在整個(gè)過(guò)程中:如果未處理的信號(hào)被傳遞給線程,那么它將影響(終止,停止,繼續(xù),被忽略)線程組的所有成員 . 每個(gè)線程都有自己的信號(hào)掩碼,由sigprocmask(2)設(shè)置,但信號(hào)可以是掛起的:對(duì)于整個(gè)進(jìn)程(即,可傳遞給線程組的任何成員),當(dāng)與kill(2)一起發(fā)送時(shí);或者與tgkill(2)一起發(fā)送的單個(gè)線程 . 對(duì)sigpending(2)的調(diào)用返回一個(gè)信號(hào)集,該信號(hào)集是整個(gè)過(guò)程中待處理的信號(hào)和為調(diào)用線程掛起的信號(hào)的并集 . 如果使用kill(2)向線程組發(fā)送信號(hào),并且線程組已經(jīng)為信號(hào)安裝了一個(gè)處理程序,那么將在沒(méi)有阻塞該線程組的線程組中任意選擇的一個(gè)成員中調(diào)用該處理程序 . 信號(hào) . 如果組中的多個(gè)線程正在等待使用sigwaitinfo(2)接受相同的信號(hào),則內(nèi)核將任意選擇其中一個(gè)線程來(lái)接收使用kill(2)發(fā)送的信號(hào) .
Linux不是SCO Unix,因?yàn)長(zhǎng)inux可能會(huì)向任何線程發(fā)出信號(hào),即使是某些線程線程正在等待信號(hào)(使用sigwaitinfo,sigtimedwait或sigwait),而某些線程則沒(méi)有 . sigwaitinfo(2)的手冊(cè)警告說(shuō),
在正常使用中,調(diào)用程序通過(guò)事先調(diào)用sigprocmask(2)來(lái)阻塞set中的信號(hào)(這樣,如果它們?cè)谶B續(xù)調(diào)用sigwaitinfo()或sigtimedwait()之間變?yōu)閽炱?#xff0c;則不會(huì)發(fā)生這些信號(hào)的默認(rèn)處置)并且不為這些信號(hào) Build 處理程序 . 在多線程程序中,應(yīng)該在所有線程中阻塞信號(hào),以防止信號(hào)在調(diào)用sigwaitinfo()或sigtimedwait()之外的線程中根據(jù)其默認(rèn)處置進(jìn)行處理 .
為信號(hào)選擇線程的代碼位于linux/kernel/signal.c(鏈接指向GitHub 's mirror). See the functions wants_signal() and completes_signal(). The code picks the first available thread for the signal. An available thread is one that doesn' t阻塞信號(hào)并且隊(duì)列中沒(méi)有其他信號(hào) . 代碼首先檢查主線程,然后檢查其他線程如果沒(méi)有線程可用,那么信號(hào)會(huì)被卡住,直到某個(gè)線程解除阻塞信號(hào)或清空其隊(duì)列 .
What happens when a thread gets the signal? 如果有信號(hào)處理程序,則內(nèi)核會(huì)使線程調(diào)用處理程序 . 大多數(shù)處理程序在線程堆棧上運(yùn)行 . 如果進(jìn)程使用sigaltstack(2)提供堆棧,則處理程序可以在備用堆棧上運(yùn)行,而使用SA_ONSTACK sigaction(2)來(lái)設(shè)置處理程序 . 內(nèi)核將一些東西推到所選的堆棧上,并設(shè)置一些線程的寄存器 .
要運(yùn)行處理程序,該線程必須在用戶空間中運(yùn)行 . 如果線程在內(nèi)核中運(yùn)行(可能是系統(tǒng)調(diào)用或頁(yè)面錯(cuò)誤),那么在它進(jìn)入用戶空間之前它不會(huì)運(yùn)行處理程序 . 內(nèi)核可以中斷一些系統(tǒng)調(diào)用,因此線程現(xiàn)在運(yùn)行處理程序,而不等待系統(tǒng)調(diào)用完成 .
信號(hào)處理程序是一個(gè)C函數(shù),因此內(nèi)核遵循體系結(jié)構(gòu)調(diào)用C函數(shù)的約定 . 每個(gè)架構(gòu),如arm,i386,powerpc或sparc,都有自己的約定 . 對(duì)于powerpc,要調(diào)用handler(signum),內(nèi)核將寄存器r3設(shè)置為signum . 內(nèi)核還將處理程序的返回地址設(shè)置為信號(hào)trampoline . 返回地址按照慣例進(jìn)入堆棧或寄存器 .
內(nèi)核在每個(gè)進(jìn)程中放置一個(gè)信號(hào)trampoline . 這個(gè)trampoline調(diào)用sigreturn(2)來(lái)恢復(fù)線程 . 在內(nèi)核中,sigreturn(2)從堆棧中讀取一些信息(如保存的寄存器) . 在調(diào)用處理程序之前,內(nèi)核已將此信息推送到堆棧上 . 如果系統(tǒng)調(diào)用中斷,內(nèi)核可能會(huì)重新啟動(dòng)調(diào)用(僅當(dāng)處理程序使用SA_RESTART時(shí)),或者使用EINTR失敗,或者返回短讀或?qū)?.
總結(jié)
以上是生活随笔為你收集整理的linux调用信号处理程序后返回,如何在Linux上执行异步信号处理程序?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux kvm安装windows,L
- 下一篇: linux 其他常用命令