信號的概念
取決于進程的要求,內(nèi)核對Signal信號有如下三種行為:
- 忽略信號
- 抓住這個信號并且對這個信號進行處理
- 采取默認行為
信號標識符Signal Identifiers

Signals#1

Signals#2
在Linux中, SIGINFO = SIGPWR | SIGIOT = SIGABRT | SIGPOLL = SIGLOST = SIGIO
- SIGABRT
函數(shù)abort將此信號發(fā)送給調(diào)用它的進程。然后,該進程終止并生成一個core file。在Linux中,在條件不滿足時,斷言assert()調(diào)用abort() 。 - SIGALRM
alarm()和setitimer()函數(shù)(帶有ITIMER_REAL標志)將此信號發(fā)送給在警報過期時調(diào)用它們的進程。 - SIGBUS
當進程發(fā)生內(nèi)存保護(這個會出發(fā)SIGSEGV)以外的硬件故障時,內(nèi)核會引發(fā)此信號。 - SIGCHLD
每當進程終止或停止時,內(nèi)核都會向進程的父進程發(fā)送此信號。由于默認情況下忽略SIGCHLD, 所以進程必須顯式的捕獲并處理他們感興趣的子進程。此信號的處理程序通常調(diào)用wait()。 - SIGCONT
當進程在停止后恢復時,內(nèi)核將此信號發(fā)送給進程。默認情況下,此信號將被忽略,但如果進程希望在繼續(xù)之后進行一個特殊的行為則可以抓住他。此信號通常由希望刷新屏幕的終端或編輯器使用。 - SIGFPE
此信號表示任何算術(shù)異常,而不僅僅是那些與浮點操作相關(guān)的異常。 - SIGHUP
當會話session的終端斷開時,內(nèi)核將此信號發(fā)送給會話領導人seesion leader。 - SIGILL
當進程試圖執(zhí)行非法機器指令時,內(nèi)核發(fā)送此信號。默認操作是終止進程并生成一個核心轉(zhuǎn)儲。進程可以選擇捕獲并處理SIGILL,但它們的行為在發(fā)生后沒有定義。 - SIGINT
當用戶輸入中斷字符(通常為Ctrl-C)時,此信號被發(fā)送到前臺進程組中的所有進程。默認行為是終止;但是,進程可以選擇 捕捉和處理這個信號,通常在結(jié)束前進行清理。 - SIGIO
處理異步IO - SIGKILL
這個信號是從kill()系統(tǒng)調(diào)用發(fā)送的;它的存在是為了向系統(tǒng)管理員提供一種絕對有效的方式來無條件地殺死一個進程。這個信號不能被捕獲或忽略,而且它結(jié)果總是終止進程。 - SIGPIPE
如果進程寫入管道,但讀取器已終止,則內(nèi)核將引發(fā)此信號。默認操作是終止進程,但是這個信號可能會被捕獲和處理。 - SIGPROF
當與ITIMER_PROF標志一起使用時,setitimer()函數(shù)將在分析計時器過期時生成此信號。默認操作是終止進程。 - SIGPWR
這個信號與系統(tǒng)有關(guān)。在linux上,它表示低電池狀態(tài)(例如在不間斷電源或UPS中)。UPS監(jiān)視守護進程將此信號發(fā)送給init,然后希望在電源斷電前完成系統(tǒng)的清理和關(guān)閉。 - SIGQUIT
當用戶提供終端退出字符(通常為Ctrl-)時,內(nèi)核會為前臺進程組中的所有進程發(fā)出此信號。默認操作是終止進程 生成一個core file。 - SIGSEGV
此信號的名稱源于分段沖突,當它嘗試無效的內(nèi)存訪問時,該信號被發(fā)送到進程。進程可以捕獲并處理此信號,但默認操作是終止進程并生成一個core dump。 - SIGSTOP
這個信號只由kill()發(fā)送。它無條件地停止一個進程,不能被捕獲或忽略。 - SIGSYS
內(nèi)核在試圖調(diào)用無效的系統(tǒng)調(diào)用時將此信號發(fā)送給進程。 - SIGTERM
此信號僅由kill()發(fā)送;它允許用戶優(yōu)雅地終止進程(默認操作)。進程可能會選擇在終止之前捕獲這個信號并清除,但被認為是粗魯?shù)刈プ∵@個信號而不立即終止。 - SIGTRAP
當內(nèi)核穿過斷點時,將此信號發(fā)送給進程。通常,調(diào)試器捕獲這個信號,而其他進程忽略它。 - SIGTSTP
當用戶提供掛起字符(通常是Ctrl-Z)時,內(nèi)核將此信號發(fā)送給前臺進程組中的所有進程。 - SIGTTIN
當試圖從其控制終端讀取時,該信號被發(fā)送到后臺的進程。默認操作是停止進程。 - SIGTTOU
當試圖寫入其控制終端時,該信號被發(fā)送到后臺的進程。默認操作是停止進程。 - SIGURG
當out-of-band(OOB)數(shù)據(jù)到達套接字上時,內(nèi)核將此信號發(fā)送給進程。帶外數(shù)據(jù)超出了本書的范圍。 - SIGUSR1 and SIGUSR2
這些信號可用于用戶定義的用途。默認操作是終止進程。 - SIGVTALRM
當使用ITIMER_VIRTUAL標志創(chuàng)建的計時器過期時,setitimer()函數(shù)將發(fā)送此信號。 - SIGWINCH
當前臺進程組中的所有進程的終端窗口大小發(fā)生變化時,內(nèi)核將引發(fā)此信號。默認情況下,進程忽略此信號,但它們可能選擇捕獲 如果他們知道終端的窗口大小,就處理它。一個程序捕捉這個信號很好的例子, 是top-嘗試調(diào)整其窗口時,它正在運行,并觀察它的反應。 - SIGXCPU
當進程超過其軟處理器限制時,內(nèi)核將引發(fā)此信號。內(nèi)核將繼續(xù)每秒發(fā)出一次此信號,直到進程退出或超過其硬處理器限制為止。 一旦超出了硬限制,內(nèi)核就會向進程發(fā)送SIGKILL。 - SIGXFSZ
當進程超過其文件大小限制時,內(nèi)核將引發(fā)此信號。默認操作是終止進程,但如果捕獲或忽略此信號,系統(tǒng)調(diào)用將返回-1,并設置errno-EFBIg。
基本信號管理
#include<signal.h>
typedef void(*sighandler_t)(int);
sighandler_t signal(int signo, sighandler_t handler);
還可以使用signal()指示內(nèi)核忽略當前進程的給定信號,或者將信號重置為默認行為。這是使用處理??梢酝ㄟ^使用特殊的值給予handler參數(shù)來是實現(xiàn)。
- SIG_DEL
設置signal的行為默認化。 - SIG_IGN
忽略此參數(shù)。
等待一個或任意信號
可用于調(diào)試和編寫演示代碼片段,POSIX定義的pause()系統(tǒng)調(diào)用將進程置于睡眠狀態(tài),直到接收到處理或終止進程的信號為止 :
#include <unistd.h>
int pause(void);
pause()只在接收到信號時返回,在這種情況下信號被處理,而pause()返回?1并將errno設置為EINTR。如果內(nèi)核引發(fā)一個被忽略的信號,進程就不會喚醒。
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;
}

測試結(jié)果
#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í)行和繼承
子進程繼承父進程的信號操作(ignore, default, handle)。

signal
/* 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]);
}