信號(hào)的概念
取決于進(jìn)程的要求惦银,內(nèi)核對(duì)Signal信號(hào)有如下三種行為:
- 忽略信號(hào)
- 抓住這個(gè)信號(hào)并且對(duì)這個(gè)信號(hào)進(jìn)行處理
- 采取默認(rèn)行為
信號(hào)標(biāo)識(shí)符Signal Identifiers
在Linux中烘浦, SIGINFO = SIGPWR | SIGIOT = SIGABRT | SIGPOLL = SIGLOST = SIGIO
- SIGABRT
函數(shù)abort將此信號(hào)發(fā)送給調(diào)用它的進(jìn)程爷怀。然后当纱,該進(jìn)程終止并生成一個(gè)core file。在Linux中,在條件不滿足時(shí),斷言assert()調(diào)用abort() 茎芋。 - SIGALRM
alarm()和setitimer()函數(shù)(帶有ITIMER_REAL標(biāo)志)將此信號(hào)發(fā)送給在警報(bào)過期時(shí)調(diào)用它們的進(jìn)程。 - SIGBUS
當(dāng)進(jìn)程發(fā)生內(nèi)存保護(hù)(這個(gè)會(huì)出發(fā)SIGSEGV)以外的硬件故障時(shí)蜈出,內(nèi)核會(huì)引發(fā)此信號(hào)田弥。 - SIGCHLD
每當(dāng)進(jìn)程終止或停止時(shí),內(nèi)核都會(huì)向進(jìn)程的父進(jìn)程發(fā)送此信號(hào)铡原。由于默認(rèn)情況下忽略SIGCHLD, 所以進(jìn)程必須顯式的捕獲并處理他們感興趣的子進(jìn)程偷厦。此信號(hào)的處理程序通常調(diào)用wait()。 - SIGCONT
當(dāng)進(jìn)程在停止后恢復(fù)時(shí)燕刻,內(nèi)核將此信號(hào)發(fā)送給進(jìn)程只泼。默認(rèn)情況下,此信號(hào)將被忽略酌儒,但如果進(jìn)程希望在繼續(xù)之后進(jìn)行一個(gè)特殊的行為則可以抓住他辜妓。此信號(hào)通常由希望刷新屏幕的終端或編輯器使用。 - SIGFPE
此信號(hào)表示任何算術(shù)異常忌怎,而不僅僅是那些與浮點(diǎn)操作相關(guān)的異常。 - SIGHUP
當(dāng)會(huì)話session的終端斷開時(shí)酪夷,內(nèi)核將此信號(hào)發(fā)送給會(huì)話領(lǐng)導(dǎo)人seesion leader榴啸。 - SIGILL
當(dāng)進(jìn)程試圖執(zhí)行非法機(jī)器指令時(shí),內(nèi)核發(fā)送此信號(hào)晚岭。默認(rèn)操作是終止進(jìn)程并生成一個(gè)核心轉(zhuǎn)儲(chǔ)鸥印。進(jìn)程可以選擇捕獲并處理SIGILL,但它們的行為在發(fā)生后沒有定義坦报。 - SIGINT
當(dāng)用戶輸入中斷字符(通常為Ctrl-C)時(shí)库说,此信號(hào)被發(fā)送到前臺(tái)進(jìn)程組中的所有進(jìn)程。默認(rèn)行為是終止片择;但是潜的,進(jìn)程可以選擇 捕捉和處理這個(gè)信號(hào),通常在結(jié)束前進(jìn)行清理字管。 - SIGIO
處理異步IO - SIGKILL
這個(gè)信號(hào)是從kill()系統(tǒng)調(diào)用發(fā)送的啰挪;它的存在是為了向系統(tǒng)管理員提供一種絕對(duì)有效的方式來無條件地殺死一個(gè)進(jìn)程信不。這個(gè)信號(hào)不能被捕獲或忽略,而且它結(jié)果總是終止進(jìn)程亡呵。 - SIGPIPE
如果進(jìn)程寫入管道抽活,但讀取器已終止,則內(nèi)核將引發(fā)此信號(hào)锰什。默認(rèn)操作是終止進(jìn)程下硕,但是這個(gè)信號(hào)可能會(huì)被捕獲和處理。 - SIGPROF
當(dāng)與ITIMER_PROF標(biāo)志一起使用時(shí)汁胆,setitimer()函數(shù)將在分析計(jì)時(shí)器過期時(shí)生成此信號(hào)梭姓。默認(rèn)操作是終止進(jìn)程。 - SIGPWR
這個(gè)信號(hào)與系統(tǒng)有關(guān)沦泌。在linux上糊昙,它表示低電池狀態(tài)(例如在不間斷電源或UPS中)。UPS監(jiān)視守護(hù)進(jìn)程將此信號(hào)發(fā)送給init谢谦,然后希望在電源斷電前完成系統(tǒng)的清理和關(guān)閉释牺。 - SIGQUIT
當(dāng)用戶提供終端退出字符(通常為Ctrl-)時(shí),內(nèi)核會(huì)為前臺(tái)進(jìn)程組中的所有進(jìn)程發(fā)出此信號(hào)回挽。默認(rèn)操作是終止進(jìn)程 生成一個(gè)core file没咙。 - SIGSEGV
此信號(hào)的名稱源于分段沖突,當(dāng)它嘗試無效的內(nèi)存訪問時(shí)千劈,該信號(hào)被發(fā)送到進(jìn)程祭刚。進(jìn)程可以捕獲并處理此信號(hào),但默認(rèn)操作是終止進(jìn)程并生成一個(gè)core dump墙牌。 - SIGSTOP
這個(gè)信號(hào)只由kill()發(fā)送涡驮。它無條件地停止一個(gè)進(jìn)程,不能被捕獲或忽略喜滨。 - SIGSYS
內(nèi)核在試圖調(diào)用無效的系統(tǒng)調(diào)用時(shí)將此信號(hào)發(fā)送給進(jìn)程捉捅。 - SIGTERM
此信號(hào)僅由kill()發(fā)送;它允許用戶優(yōu)雅地終止進(jìn)程(默認(rèn)操作)虽风。進(jìn)程可能會(huì)選擇在終止之前捕獲這個(gè)信號(hào)并清除棒口,但被認(rèn)為是粗魯?shù)刈プ∵@個(gè)信號(hào)而不立即終止。 - SIGTRAP
當(dāng)內(nèi)核穿過斷點(diǎn)時(shí)辜膝,將此信號(hào)發(fā)送給進(jìn)程无牵。通常,調(diào)試器捕獲這個(gè)信號(hào)厂抖,而其他進(jìn)程忽略它茎毁。 - SIGTSTP
當(dāng)用戶提供掛起字符(通常是Ctrl-Z)時(shí),內(nèi)核將此信號(hào)發(fā)送給前臺(tái)進(jìn)程組中的所有進(jìn)程验游。 - SIGTTIN
當(dāng)試圖從其控制終端讀取時(shí)充岛,該信號(hào)被發(fā)送到后臺(tái)的進(jìn)程保檐。默認(rèn)操作是停止進(jìn)程。 - SIGTTOU
當(dāng)試圖寫入其控制終端時(shí)崔梗,該信號(hào)被發(fā)送到后臺(tái)的進(jìn)程夜只。默認(rèn)操作是停止進(jìn)程。 - SIGURG
當(dāng)out-of-band(OOB)數(shù)據(jù)到達(dá)套接字上時(shí)蒜魄,內(nèi)核將此信號(hào)發(fā)送給進(jìn)程扔亥。帶外數(shù)據(jù)超出了本書的范圍。 - SIGUSR1 and SIGUSR2
這些信號(hào)可用于用戶定義的用途谈为。默認(rèn)操作是終止進(jìn)程旅挤。 - SIGVTALRM
當(dāng)使用ITIMER_VIRTUAL標(biāo)志創(chuàng)建的計(jì)時(shí)器過期時(shí),setitimer()函數(shù)將發(fā)送此信號(hào)伞鲫。 - SIGWINCH
當(dāng)前臺(tái)進(jìn)程組中的所有進(jìn)程的終端窗口大小發(fā)生變化時(shí)粘茄,內(nèi)核將引發(fā)此信號(hào)。默認(rèn)情況下秕脓,進(jìn)程忽略此信號(hào)柒瓣,但它們可能選擇捕獲 如果他們知道終端的窗口大小,就處理它吠架。一個(gè)程序捕捉這個(gè)信號(hào)很好的例子, 是top-嘗試調(diào)整其窗口時(shí)芙贫,它正在運(yùn)行,并觀察它的反應(yīng)傍药。 - SIGXCPU
當(dāng)進(jìn)程超過其軟處理器限制時(shí)磺平,內(nèi)核將引發(fā)此信號(hào)。內(nèi)核將繼續(xù)每秒發(fā)出一次此信號(hào)拐辽,直到進(jìn)程退出或超過其硬處理器限制為止拣挪。 一旦超出了硬限制,內(nèi)核就會(huì)向進(jìn)程發(fā)送SIGKILL俱诸。 - SIGXFSZ
當(dāng)進(jìn)程超過其文件大小限制時(shí)媒吗,內(nèi)核將引發(fā)此信號(hào)。默認(rèn)操作是終止進(jìn)程乙埃,但如果捕獲或忽略此信號(hào),系統(tǒng)調(diào)用將返回-1锯岖,并設(shè)置errno-EFBIg介袜。
基本信號(hào)管理
#include<signal.h>
typedef void(*sighandler_t)(int);
sighandler_t signal(int signo, sighandler_t handler);
還可以使用signal()指示內(nèi)核忽略當(dāng)前進(jìn)程的給定信號(hào),或者將信號(hào)重置為默認(rèn)行為出吹。這是使用處理遇伞。可以通過使用特殊的值給予handler參數(shù)來是實(shí)現(xiàn)捶牢。
- SIG_DEL
設(shè)置signal的行為默認(rèn)化鸠珠。 - SIG_IGN
忽略此參數(shù)巍耗。
等待一個(gè)或任意信號(hào)
可用于調(diào)試和編寫演示代碼片段,POSIX定義的pause()系統(tǒng)調(diào)用將進(jìn)程置于睡眠狀態(tài)渐排,直到接收到處理或終止進(jìn)程的信號(hào)為止 :
#include <unistd.h>
int pause(void);
pause()只在接收到信號(hào)時(shí)返回炬太,在這種情況下信號(hào)被處理,而pause()返回?1并將errno設(shè)置為EINTR驯耻。如果內(nèi)核引發(fā)一個(gè)被忽略的信號(hào)亲族,進(jìn)程就不會(huì)喚醒。
Examples
//test SIGINT
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
/* handler for SIGINT */
static void sigint_handler (int signo) {
/*
* Technically, you shouldn't use printf() in a
* signal handler, but it isn't the end of the
* world. I'll discuss why in the section
* "Reentrancy."
*/
printf ("Caught SIGINT!\n");
exit (EXIT_SUCCESS);
}
int main (void) {
/*
* Register sigint_handler as our signal handler
* for SIGINT.
*/
if (signal (SIGINT, sigint_handler) == SIG_ERR) {
fprintf (stderr, "Cannot handle SIGINT!\n");
exit (EXIT_FAILURE);
}
for (;;)
pause ();
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
/* handler for SIGINT and SIGTERM */
static void signal_handler (int signo) {
if (signo == SIGINT)
printf ("Caught SIGINT!\n");
else if (signo == SIGTERM)
printf ("Caught SIGTERM!\n");
else {
/* this should never happen */
fprintf (stderr, "Unexpected signal!\n");
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}
int main (void) {
/*
* Register signal_handler as our signal handler
* for SIGINT.
*/
if (signal (SIGINT, signal_handler) == SIG_ERR) {
fprintf (stderr, "Cannot handle SIGINT!\n");
exit (EXIT_FAILURE);
}
/*
* Register signal_handler as our signal handler
* for SIGTERM.
*/
if (signal (SIGTERM, signal_handler) == SIG_ERR) {
fprintf (stderr, "Cannot handle SIGTERM!\n");
exit (EXIT_FAILURE);
}
/* Reset SIGPROF's behavior to the default. */
if (signal (SIGPROF, SIG_DFL) == SIG_ERR) {
fprintf (stderr, "Cannot reset SIGPROF!\n");
exit (EXIT_FAILURE);
}
/* Ignore SIGHUP. */
if (signal (SIGHUP, SIG_IGN) == SIG_ERR) {
fprintf (stderr, "Cannot ignore SIGHUP!\n");
exit (EXIT_FAILURE);
}
for (;;)
pause ();
return 0;
}
執(zhí)行和繼承
子進(jìn)程繼承父進(jìn)程的信號(hào)操作(ignore, default, handle)可缚。
/* handle SIGINT, but only if it isn't ignored */
if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
if (signal (SIGINT, sigint_handler) == SIG_ERR)
fprintf (stderr, "Failed to handle SIGINT!\n");
}
/* handle SIGQUIT, but only if it isn't ignored */
if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) {
if (signal (SIGQUIT, sigquit_handler) == SIG_ERR)
fprintf (stderr, "Failed to handle SIGQUIT!\n");
}
Mapping Signal Numbers to Strings
#define _GNU_SOURCE
#include <string.h>
char * strsignal (int signo);
static void signal_handler (int signo) {
printf ("Caught %s\n", sys_siglist[signo]);
}