軟件中斷
。異步事件
的方法。SIG
開頭。在頭文件signal.h(其中include的bits/signum.h)中,信號名都被定義為正整數常量,不存在編號為0的信號。kill函數對信號編號0有特殊的應用。
很多條件可以產生信號:
- 用戶按下某些終端鍵時:Ctrl+C、Ctrl+/、Ctrl+Z
- 硬件異常產生信號:除數為0、無效的內存引用
- 進程調用kill函數可將任意信號發送給另一個進程或進程組
- 當檢測到某些軟件條件已經發生,并應將其通知有關進程時產生信號。如:SIGURG(網絡連接上傳來帶外數據)、SIGPipE(在管道的讀進程已經終止后,一個進程寫此管道)、SIGALRM(進程所設置的定時器超時)
信號是異步事件的經典實例。產生信號的事件對進程而言是隨機出現的。進程不能簡單地測試一個變量(如errno)來判斷是否發生了一個信號,而是必須告訴內核“在此信號發生時,請執行下列操作”。
當某個信號出現時,可以告訴內核按下列3種方式之一進行處理,稱之為信號的處理
- 忽略此信號。SIG_IGN。只有兩種信號不能被忽略:SIGKILL和SIGSTOP。原因是:它們向內核和超級用戶提供了使進程終止或停止的可靠方法。另外,如果忽略某些由硬件異常產生的信號(如非法內存引用或除以0),則進程的運行行為是未定義的。
- 捕捉信號。即通知內核在某種信號發生后,調用一個用戶函數。
- 執行系統默認動作。對大多數信號的默認動作是終止該進程。
終止+core。大多數Unix系統調試程序都使用core文件檢查進程終止時的狀態。
在下列條件下不產生core文件:
- 進程是設置用戶ID的,而且當前用戶并非程序文件的所有者
- 進程是設置組ID的,而且當前用戶并非程序文件的組所有者
- 用戶沒有寫當前工作目錄的權限
- 文件已存在,而且用戶對該文件沒有寫權限
4個平臺對各種signal的支持及默認處理方式
- SIGABRT。調用abort函數時產生此信號。
- SIGALRM。當用alarm函數設置的定時器超時時,產生此信號。
- SIGCHLD。在一個進程終止或停止時,該信號被送給其父進程。按系統默認,將忽略此信號。
- SIGFPE。表示算術運算異常,如除以0、浮點溢出等。
- SIGHUP。如果終端接口檢測到一個連接斷開,則將此信號送給與該終端相關的控制進程(會話首進程)。通常使用此信號通知守護進程再次讀取它們的配置文件。選用此信號的理由是:守護進程不會有控制終端,通常決不會接收到這種信號。
- SIGILL。表示進程執行一條非法硬件指令。
- SIGINT。當用戶按下中斷鍵Ctrl+C時,終端驅動程序產生此信號并發送至前臺進程組的每一個進程。
- SIGIO。指示一個異步I/O事件。
- SIGTERM。由kill命令發送的系統默認終止信號。
- SIGKILL。不能捕獲或忽略。它向管理員提供了一紅殺死任一進程的可靠方法。
- SIGPIPE。如果在管道的讀進程已終止時寫管道,則產生此信號。
- SIGQUIT。當用戶在終端上按下退出鍵Ctrl+/時,終端驅動程序產生此信號并發送給前臺進程組中的所有進程。此信號除了終止前臺進程組(和SIGINT一樣),同時產生一個core文件。
- SIGSEGV。指示進程進行了一次無效的內存引用。
- SIGTSTP。交互停止信號。當用戶在終端上按下掛起鍵Ctrl+Z時,終端驅動程序產生此信號,并發送至前臺進程組的所有進程。
- SIGSTOP。類似于交互停止信號(SIGTSTP),但它不能被捕獲或忽略。
- SIGCONT。此作業控制信號發送給需要繼續運行,但當前處于停止狀態的進程。
- SIGTTIN。當一個后臺進程組進程試圖讀其控制終端時,終端驅動程序產生此信號。下列情況例外:1. 讀進程忽略或阻塞此信號;2. 讀進程所屬的進程組是孤兒進程組,此時讀操作返回出錯,errno設置為EIO
- SIGTTOU。當一個后臺進程組進程試圖寫其控制終端時,終端驅動程序產生此信號。
- SIGURG。通知進程已經發生一個緊急情況。如帶外數據到達。
- SIGUSR1、SIGUSR2。用戶定義的信號,可用于應用程序。
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
Returns: PRevious disposition of signal (see following) if OK, SIG_ERR on error
typedef void Sigfunc(int);
Sigfunc* signal(int, Sigfunc*);
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1
exec,程序啟動
當exec執行一個程序時,所有信號都被設置為它們的默認動作,除非調用exec的進程忽略該信號(則繼續保持忽略)。也就是說,exec函數將原先設置為要捕獲的信號都更改為默認動作,其他保持不變。因為當exec一個新程序時,信號處理程序的地址很可能在新程序中已無意義。
fork,進程創建
當一個進程調用fork時,其子進程繼承父進程的信號處理方式。因為信號處理程序的地址在子進程中是有意義的。
again:
if ((n = read(fd, buf, BUFFSIZE)) < 0) {
if (errno == EINTR)
goto again; /* just an interrupted system call */
/* handle other errors */
}
- 如果進程正在執行malloc,而在信號處理程序中又再次調用malloc,這時會?
- 如果進程正在執行getpwnam,這是將其結果存放在靜態存儲單元中的函數,而在信號處理程序中又再次調用getpwnam,這時會?
可重入的
,并被稱為異步信號安全
的。不可重入的
,因為:
- 它們使用靜態數據結構
- 它們調用malloc或free
- 它們是標準的I/O函數。標準I/O庫的很多實現都以不可重入方式使用全局數據結構。
遞送
了一個信號。在信號產生和遞送之間的時間間隔內,稱信號是未決
的。信號屏蔽字
,它規定了當前要阻塞遞送到該進程的信號集。進程可以調用sigprocmask函數
來檢測和更改其當前信號屏蔽字。sigpending函數
來判定哪些信號是設置為阻塞并處于未決狀態的。排隊
。除非支持POSIX.1實時擴展,否則大多數Unix并不對信號排隊,而只遞送一次。
#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
Both return: 0 if OK, −1 on error
- pid > 0,發送給進程ID為pid的進程
- pid == 0,發送給與發送進程屬于同一進程組的所有進程
- pid < 0,發送給其進程組ID等于pid絕對值,而且發送進程具有權限向其發送信號的所有進程
- pid == -1,發送給發送進程具有權限向它們發送信號的所有進程
關于發送信號的權限
- 超級用戶可將信號發送給任一進程。
- 非超級用戶,其基本規則是發
新聞熱點
疑難解答