您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“linux signal的作用是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“linux signal的作用是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
linux signal用來通知進程某個特定事件的發生或者是讓進程執行某個特定的處理函數;signal即信號,是Unix家族中一個古老的通信機制;信號可以來自終端的鍵盤字符輸入,比如control-C觸發的SIGINIT,也可以來自與硬件或軟件有關的異常,比如應用程序訪問了無效地址觸發的SIGSEGV,定時器到期觸發的SIGALARM等。
linux signal用來做什么?
Linux中的信號處理機制
信號(Signal)是Unix家族中一個古老的通信機制,主要用來通知進程某個特定事件的發生,或者是讓進程執行某個特定的處理函數。說它古老,是因為它在第一代Unix系統中就已經存在了。
信號可以來自終端(terminal)的鍵盤字符輸入,比如control-C觸發的SIGINIT;也可以來自與硬件或軟件有關的異常,比如應用程序訪問了無效地址觸發的SIGSEGV(segmentation fault),定時器到期觸發的SIGALARM等。這些信號都是由內核發送給進程的。
進程收到的信號還可以來自于其他進程。但不是所有的進程都可以向其他任意一個進程發送信號,只有具有root權限的super user才可以這么做,對于普通user的進程,只能向屬于同一user的進程發送信號。
那進程可以向內核發送信號嗎?可以是可以,但內核線程是不會響應的,發了也白發,除非……你修改內核代碼。
通常信號被認為是一種異步的機制,但是在Linux的代碼中,以下由異常引起的信號也被稱為"synchronous"的:
#define SYNCHRONOUS_MASK \ (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS))
這里我們稱接收信號的進程為“目標進程”。傳統的信號發送函數是kill(),這名字看起來好嚇人,感覺好像是目標進程馬上就要被“殺”掉了。事實上,雖然各路信號都用kill()來發送,但真正要"kill"掉進程的,只占一小部分。當然,現在已經有了功能更強,名字也更友好的sigqueue()了。
來看下兩者的函數原型:
int kill(pid_t pid, int sig);int sigqueue(pid_t pid, int sig, const union sigval value);
pid代表目標進程的PID。Linux中進程的PID都是正數,那參數pid的值如果是0或者負數,是不是就是非法的呢?非也,事實上,0和負數在這里都是有其他用途的。Linux里有個進程組的概念(process group),表示一類進程的集合。在kill()中,參數pid為"0"說明信號是發給當前進程所在進程組的所有進程,小于"-1"則是向編號為-pid的進程組發送信號。
__kill_pgrp_info(sig, info, pid ? find_vpid(-pid) : task_pgrp(current));
pid為"-1"表示發送給除Init進程和自身以外的所有進程,或者說是除自身以外的所有pid大于1的進程。
for_each_process(p) {
if (task_pid_vnr(p) > 1 && !same_thread_group(p, current))
...
如果這里pid是進程自己的PID,那么就是進程給自身發送信號。為此,Linux還提供了一個更簡潔的接口:raise()函數。
kill(getpid(), sig) --> raise(sig)
需要注意的是,在sigqueue()中,不能通過將參數pid的值設為負數來向整個進程組發送信號。
sig代表要發送信號的編號,Linux中的信號編號是從1開始的,那參數sig的值如果為0會怎樣呢?這里的0也有妙用,sig為"0"時并不會真正的往目標進程(或進程組)發送信號,而是用來檢測目標進程(或進程組)是否存在。
至于sigqueue增加的第三個參數,其定義是這樣的:
union sigval {
int sival_int;
void __user *sival_ptr;};
傳統的信號是沒有傳遞消息的功能的,sigval算是稍微擴展了一下信號的通信能力。比如,通信雙方可以事先約定某些事件為特定的int值,這個"sival_int"就可以用來保存具體的int值,目標進程可以據此來區分不同的事件,做出不同的響應。當然,這種方法傳遞的消息內容受限,且不易擴展,因而不適合用作常規的通信手段。
就算是進程之間發送信號,那也是要經過內核的,可以理解成是被內核“截獲”了吧。
由于內核態和用戶態的切換操作在不同的硬件體系架構上是不同的,而且有一些信號,比如SIGCHLD和SIGSTOP,其實現也是和架構相關的,所以Linux中signal機制的很多代碼都是放在架構相關的目錄下的,比如"/arch/arm/kernel/signal.c"。
一個信號的相關信息在內核中用siginfo_t結構體表示:
siginfo_t{
int si_signo;
int si_sicode;
union __sifields _sifields;
...}
si_signo是信號的編號,從1到64的值都是合法的。
si_sicode記錄了信號的來源,比如SI_USER表示信號是由進程調用kill()發出的,SI_QUEUE是由進程調用sigqueue()發出的,SI_KERNEL則說明該信號由內核產生的。
_sifields對不同的信號會有不同的含義,通常包括信號發送進程的si_pid,發送進程所屬user的si_uid等。對于由sigqueue()發送的信號,還包括"sigval "參數所攜帶的附加信息。
內核在截獲到一個進程發送的信號后,會首先做一系列的檢查,比如該信號的值是否合法啦,進程有沒有發送這個信號的權限啦。如果檢查通過,就調用copy_from_user()將該信號的相關信息復制到siginfo_t結構體中。
讀到這里,這篇“linux signal的作用是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。