國(guó)際網(wǎng)站推廣專員招聘做推廣app賺錢的項(xiàng)目
??? ? ? ? ?收發(fā)信號(hào)思想是 Linux 程序設(shè)計(jì)特性之一,一個(gè)信號(hào)可以認(rèn)為是一種軟中斷,通過用來向進(jìn)程通知異步事件。
? ? ? ? 本文講述的 信號(hào)處理內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解信號(hào)編程。
kill(2)
遵循 POSIX.1 - 2008
1.庫(kù)
標(biāo)準(zhǔn) c 庫(kù),libc, -lc
2.接口定義
? ? ? ? 這個(gè)接口依?_POSIX_C_SOURCE 特性測(cè)試宏。
#include <signal.h>int kill(pid_t pid, int sig);
3.接口描述
????????kill() 系統(tǒng)調(diào)用可以用來向任何進(jìn)程組或者進(jìn)程發(fā)送任何信號(hào)。
? ? ? ??如果 pid 是正值,那么信號(hào) sig 是發(fā)送給 pid 指定的進(jìn)程。
? ? ? ? 如果 pid 是 0,信號(hào) sig 是發(fā)送給調(diào)用進(jìn)程所在進(jìn)程組的所有進(jìn)程。
? ? ? ? 如果 pid 是 -1,那么信號(hào) sig 會(huì)發(fā)送給所有調(diào)用進(jìn)程具有發(fā)送權(quán)限的進(jìn)程,除了 1 號(hào)進(jìn)程(init),具體下面會(huì)討論。
? ? ? ? 如果 pid 小于 -1,那么信號(hào) sig 會(huì)發(fā)送給 -pid 指定進(jìn)程的進(jìn)程組里所有的進(jìn)程。
? ? ? ? 如果 sig 是 0,那么不會(huì)發(fā)送任何信號(hào),但是仍然會(huì)進(jìn)行進(jìn)程是否存在和是否有權(quán)限等相關(guān)檢查,這個(gè)就可以用來檢查是否存在允許調(diào)用者發(fā)送信號(hào)的進(jìn)程 ID 或者進(jìn)程組 ID 存在。
? ? ? ? 對(duì)于一個(gè)具有發(fā)送信號(hào)權(quán)限的進(jìn)程來說,它要么是特權(quán)的(Linux 下需要具有目標(biāo)進(jìn)程用戶名字空間的 CAP_KILL 能力),要么發(fā)送進(jìn)程的真實(shí)或者有效的用戶 ID 和目標(biāo)進(jìn)程的真實(shí)或者保存的 set-user-ID?相同。對(duì)于 SIGCONT 信號(hào),發(fā)送和接收進(jìn)程屬于同一會(huì)話即可。(一些歷史版本的規(guī)則可能不太一樣,可以參考注意章節(jié)。)
4.返回值
? ? ? ? 一旦成功(至少有一個(gè)信號(hào)發(fā)送出去了),就會(huì)返回 0。失敗時(shí),會(huì)返回 -1,具體錯(cuò)誤信息通過 errno 來指示。
? ? ? ? 錯(cuò)誤代碼如下:
EINVAL | 指定的信號(hào)不可用 |
EPERM | 調(diào)用進(jìn)程沒有向目標(biāo)進(jìn)程組任何進(jìn)程發(fā)送信號(hào)的權(quán)限 |
ESRCH | 目標(biāo)進(jìn)程或者進(jìn)程組不存在。注意:一個(gè)存在的進(jìn)程可能是一個(gè)僵尸,即已經(jīng)被終止執(zhí)行(terminated)但是還沒有 wait(2) 等待 |
5.歷史
? ? ? ? 在不同的 Linux 內(nèi)核版本上,Linux 對(duì)非特權(quán)進(jìn)程向其他進(jìn)程發(fā)送信號(hào)實(shí)施了不同的策略。在 Linux 1.0 到 1.2.2 中,如果發(fā)送進(jìn)程的有效用戶 ID 和目標(biāo)的有效用戶 ID 匹配或者它們的真實(shí) ID 匹配,那么就可以發(fā)送信號(hào)?。在 Linux 1.2.3 到 1.3.77,只要發(fā)送進(jìn)程的有效用戶 ID 和目標(biāo)進(jìn)程的有效或者真實(shí) ID 匹配就可以發(fā)送信號(hào)。目前的策略是遵循 POSIX.1,并且在 Linux 1.3.78 中引入。
?6.注意
? ? ? ? 對(duì)于 init 進(jìn)程,也就是 1 號(hào)進(jìn)程,只能向它發(fā)送它明確安裝了信號(hào)處理函數(shù)的信號(hào)。這樣做是為了保證系統(tǒng)不被偶然情況宕機(jī)。
? ? ? ? POSIX.1 要求 kill(-1,sig) 向調(diào)用者所有能發(fā)送的進(jìn)程發(fā)送信號(hào),除了一些實(shí)現(xiàn)定義的系統(tǒng)進(jìn)程。Linux 允許進(jìn)程向自己發(fā)送信號(hào),但是 kill(-1,sig) 不會(huì)向調(diào)用進(jìn)程發(fā)送。
? ? ? ? POSIX.1 要求如果進(jìn)程向自己發(fā)送信號(hào),如果發(fā)送線程沒有阻塞信號(hào),并且其他線程阻塞了該信號(hào)或者沒有通過 sigwait(3) 等待該信號(hào),那么在 kill() 返回前至少要向發(fā)送線程發(fā)生一個(gè)非阻塞信號(hào)。
7.BUGS
? ? ? ? Linux 2.6 后一直到 2.6.7,該接口一直存在一個(gè) bug:在向進(jìn)程組進(jìn)程發(fā)送信號(hào)時(shí),只要進(jìn)程里有哪個(gè)進(jìn)程沒有權(quán)限發(fā)送信號(hào),接口就會(huì)返回 EPERM。即使返回這個(gè)錯(cuò)誤,信號(hào)還是發(fā)送給了有權(quán)限發(fā)送的進(jìn)程了。
8.代碼
? ? ? ? 下面是一個(gè)父進(jìn)程通過 kill() 殺死子進(jìn)程的例子。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>int main(void){pid_t retVal;retVal = fork();if(retVal > 0){int i = 0;while(i++ < 5){printf("in the parent process.\n");sleep(1);}//kill the child processkill(retVal, SIGKILL);} else if (retVal == 0){int i = 0;//will not ever get to 15, because//the parent process will kill itwhile(i++ < 15){printf("In the child process.\n");sleep(1);}} else {//something bad happened.printf("Something bad happened.");exit(EXIT_FAILURE);}return 0;}
?
tkill(2)
遵循 Linux
1.庫(kù)
標(biāo)準(zhǔn) c 庫(kù),libc, -lc
2.接口定義
#include <signal.h> /* Definition of SIG* constants */#include <sys/syscall.h> /* Definition of SYS_* constants */#include <unistd.h>[[deprecated]] int syscall(SYS_tkill, pid_t tid, int sig);#include <signal.h>int tgkill(pid_t tgid, pid_t tid, int sig);Note: glibc provides no wrapper for tkill(), necessitating theuse of syscall(2).
3.接口描述
? ? ? ? tgkill() 向線程組 tgid 中的線程 tid 發(fā)送信號(hào) sig。(相反,kill(2) 只能用來向進(jìn)程(線程組)發(fā)送信號(hào),信號(hào)會(huì)被發(fā)送給進(jìn)程中的任意線程。)
? ? ? ? tkill() 是 tgkill() 的過時(shí)版本。它只允許指定目標(biāo)線程 ID,這會(huì)導(dǎo)致線程 ID 回收重新分配時(shí)信號(hào)發(fā)送到錯(cuò)誤的線程。盡量避免使用這個(gè)系統(tǒng)調(diào)用。
? ? ? ? 這些都是原始系統(tǒng)調(diào)用接口,只能被線程庫(kù)內(nèi)部使用。
4.返回值
? ? ? ? 一旦成功,就會(huì)返回 0。失敗時(shí),會(huì)返回 -1,具體錯(cuò)誤信息通過 errno 來指示。
? ? ? ? 錯(cuò)誤代碼如下:
EAGAIN | sig 是實(shí)時(shí)信號(hào)并且達(dá)到了 RLIMIT_SIGPENDING 資源限制 |
EAGAIN | sig 是一個(gè)實(shí)時(shí)信號(hào),并且內(nèi)核內(nèi)存不足 |
EINVAL | 線程 ID、線程組 ID或者信號(hào) 不合法 |
EPERM | 權(quán)限拒絕。對(duì)于需要的權(quán)限,參考 kill(2) |
ESRCH | 指定的進(jìn)程不存在 |
5.歷史
? ? ? ? tkill() ? ? ? ? Linux 2.4.19/2.5.4
? ? ? ? tgkill() ? ? ? ?Linux 2.5.75,glibc 2.30
?6.注意
? ? ? ?對(duì)于進(jìn)程組的解釋,可以參考 clone(2) 的CLONE_THREAD 描述。
?