Linux信号 二 信号处理函数注册
生活随笔
收集整理的這篇文章主要介紹了
Linux信号 二 信号处理函数注册
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
每一個信號都有一個信號處理函數,可以是SIG_IGN, SIG_DFL或者是用戶自定義的處理函數。使用用戶自定義的處理函數需要注冊,注冊接口有如下兩種。
第一種是signal調用
#include <signal.h>/*** sighandler_t是GNU的擴展,如果在glibc下面使用的話,編譯的時候需要加上-D_GNU_SOURCE* 或者手動定義*/ typedef void (*sighandler_t)(int);/*** 為信號signum注冊信號處理函數handler* 成功返回該信號之前的處理函數,失敗返回SIG_ERR并將失敗原因填寫到errno中*/ sighandler_t signal(int signum, sighandler_t handler);使用signal調用會有兼容性問題,尤其是移植到其它UNIX系統上,所以推薦使用第二種信號注冊函數sigaction,該函數功能相對signal而言,能夠提供更多功能。
#include <signal.h> /*** 注冊信號處理函數,成功返回0,失敗返回-1并置errno* 參數act存儲待注冊的信號處理函數結構體* 如果oldact非空的話,舊的信號處理函數會存儲到該結構體中*/ int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void); };該結構在注冊信號處理函數sigaction中使用 1. sa_handler是一個參數為信號值的處理函數 2. sa_sigaction也是一個信號處理函數,不過它有三個參數,能夠獲取到處信號值以外更多信息,當sa_flags中包含SA_SIGINFO標志位的時候需要用到該函數。 3. sa_mask是信號處理函數執行期間的屏蔽信號集。就是說在信號處理函數執行期間,屏蔽某些信號。但是不是所有信號都能夠被屏蔽,SIGKILL和SIGSTOP這兩個信號就無法屏蔽,因為操作系統自身要能夠控制住進程。 4. sa_flags可以是下面這些值的集合:1. SA_NOCLDSTOP,這個標志位只用于SIGCHLD信號。父進程可以檢測子進程三個事件,子進程終止、子進程停止、子進程回復。SA_NOCLDSTOP標志位用于控制后兩個事件。即一旦父進程為SIGCHLD信號設置了這個標志位,那么子進程停止和子進程恢復這兩件事情,就無需向父進程發送SIGCHLD信號2. SA_NOCLDWAIT這個標志只用于SIGCHLD信號,它可控制子進程終止時候的行為,如果父進程為SIGCHLD設置了SA_NOCLDWAIT標志位,那么子進程終止退出時,就不會進入僵尸狀態,而是直接自行了斷。但是對Linux而言,子進程仍然會發送SIGCHLD信號,這點和上面的SA_NOCLDSTOP略有不同。3. SA_ONESHOT和SA_RESETHAND這兩個標志位本質是一樣的,表示信號處理函數是一次性的,信號遞送出去以后,信號處理函數便恢復成默認值SIG_DFL.4. SA_NODEFER和SA_NOMASK這兩個標志位的作用是一樣的,信號處理函數執行期間,不阻塞當前信號。5. SA_RESTART這個標志位表示,如果系統調用被信號中斷,則不返回錯誤,而是自動重啟系統調用。6. SA_SIGINFO這個標志位表示信號發送者會提供額外的信息。這種情況下,信號處理函數應該為三參數的函數。 當sa_flags含有SA_SIGINFO的時候 ,需要使用帶三個參數的處理函數: void handler(int sig, siginfo_t *info, void *ucontext) {... }第一個參數 sig 為信號值 第三個參數 ucontext,該結構體提供了進程上下文信息,通常都不會使用到該參數,具體細節 可參考man sigreturn第二個參數 info 是一個siginfo_t類型的指針,包含了信號更多的信息。該結構體如下:siginfo_t {int si_signo; /* 信號值 */int si_errno; /* An errno value */int si_code; /* 信號來源,可以通過該值來判斷信號來源* 可選值及含義* SI_USER : 調用kill 或 raise的用戶進程* SI_TKILL :調用tkill或tgkill的用戶進程* SI_QUEUE : 調用sigqueue的用戶進程* SI_MESGQ : 消息到達POSIX消息隊列* SI_KERNEL : 內核產生的信號* SI_ASYNCIO : 異步I/O操作完成* SI_TIMER: POSIX定時器到期*/int si_trapno; /* Trap number that causedhardware-generated signal(unused on most architectures) */pid_t si_pid; /* 信號發送進程ID */uid_t si_uid; /* 信號發送進程這是用戶ID */int si_status; /* Exit value or signal */clock_t si_utime; /* User time consumed */clock_t si_stime; /* System time consumed */sigval_t si_value; /* 使用sigqueue函數發送信號時攜帶的伴隨數據 */int si_int; /* POSIX.1b signal */void *si_ptr; /* POSIX.1b signal */int si_overrun; /* Timer overrun count;POSIX.1b timers */int si_timerid; /* Timer ID; POSIX.1b timers */void *si_addr; /* Memory location which caused fault */long si_band; /* Band event (was int inglibc 2.3.2 and earlier) */int si_fd; /* File descriptor */short si_addr_lsb; /* Least significant bit of address(since Linux 2.6.32) */void *si_lower; /* Lower bound when address violationoccurred (since Linux 3.19) */void *si_upper; /* Upper bound when address violationoccurred (since Linux 3.19) */int si_pkey; /* Protection key on PTE that causedfault (since Linux 4.6) */void *si_call_addr; /* Address of system call instruction(since Linux 3.5) */int si_syscall; /* Number of attempted system call(since Linux 3.5) */unsigned int si_arch; /* Architecture of attempted system call(since Linux 3.5) */ } 上面的sigval_t結構體定義如下: union sigval {int sival_int;void *sival_ptr; } 通過指定sigqueue函數的第三個參數,可以傳遞給一個int值或者指針值個目標進程。考慮 到不同的進程有各自獨立的地址空間,傳遞指針到另一個進程幾乎沒有意義。參考資料:
1. 《Linux 環境編程,從應用到內核》高峰,李彬著
2.?? man signal : https://linux.die.net/man/2/signal
????? man sigaction : http://www.man7.org/linux/man-pages/man2/sigaction.2.html
總結
以上是生活随笔為你收集整理的Linux信号 二 信号处理函数注册的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统怎么设置c盘启动 &quot
- 下一篇: Linux信号 三 信号发送接口集合