[APUE]第十章 信號

信號概念

不存在編號爲0的信號。

產生信號的方式:

1          當用戶按某些終端鍵時,引發終端產生信號。

2          硬件異常產生信號,比如SIGSEGV信號。

3          進程調用kill函數可將信號發送給另外一個進程或者進程組。

4          當檢測到某種條件發生時,並應將其通知有關進程時也產生信號。比如SIGPIPE信號。

應用程序對產生的信號有三種方式進行處理

1          忽略信號

2          系統默認

3          安裝信號處理函數,讓信號處理函數來處理

 

kill –l 可以查看系統中的信號編號

ubuntu 信號集

root@LeoK:~/APUE/8_test# kill -l
 1)SIGHUP      2) SIGINT        3) SIGQUIT     4) SIGILL         5)SIGTRAP
 6)SIGABRT    7) SIGBUS       8) SIGFPE        9) SIGKILL       10)SIGUSR1
11) SIGSEGV     12)SIGUSR2     13) SIGPIPE      14) SIGALRM   15) SIGTERM
16) SIGSTKFLT  17) SIGCHLD    18) SIGCONT    19) SIGSTOP     20)SIGTSTP
21) SIGTTIN      22)SIGTTOU    23) SIGURG      24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM        27) SIGPROF     28)SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS        34)SIGRTMIN 35) SIGRTMIN+1      36) SIGRTMIN+2      37) SIGRTMIN+3
38) SIGRTMIN+4      39) SIGRTMIN+5      40)SIGRTMIN+6      41) SIGRTMIN+7      42) SIGRTMIN+8
43) SIGRTMIN+9      44) SIGRTMIN+10    45)SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50)SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55)SIGRTMAX-9      56) SIGRTMAX-8      57) SIGRTMAX-7
58) SIGRTMAX-6      59) SIGRTMAX-5      60)SIGRTMAX-4      61) SIGRTMAX-3      62) SIGRTMAX-2
63) SIGRTMAX-1      64) SIGRTMAX

下列情況是不產生core爲

1進程是設置用戶ID的,而且當前用戶並非程序文件的所有者

2進程是設置了組ID的,而且當前用戶並非程序文件的所有者

3用戶沒有寫當前用戶的權限

4該文件太大

 

SIGPIPE信號生成

tips:

調用execl 子進程的信號處理函數都會被沖掉,使信號處理函數變成默認行爲。

當一個進程調用fork的時候,其子進程繼承父進程的信號處理方式

 

 

signal信號安裝函數

typedef void sig_dispose(int sig_no);
sig_dispose signal(sig_dispose func1);

其中函數地址可以指定如下宏

#ifndef __ASSEMBLY__
typedef void __signalfn_t(int);
typedef __signalfn_t *__sighandler_t;
typedef void __restorefn_t(void);
typedef __restorefn_t *__sigrestore_t;
#define SIG_DFL      ((__sighandler_t)0) /* default signal handling */
#define SIG_IGN      ((__sighandler_t)1) /* ignore signal */
#define SIG_ERR      ((__sighandler_t)-1)         /* error return from signal */
#endif

不可靠信號(博客中有一篇主要講可靠信號和不可靠信號之間的區別)

 

中斷系統調用:

對於正在執行低速系統調用的時候,收到信號,那麼進程就會捕捉到這個信號,中斷這個低速的系統調用,並且把errno設置爲EINTR表示被信號中斷了。

可重入函數

不可重入函數的原因是api內部使用了全局靜態數據結構,每一個進程調用的時候,會寫亂這個全局數據結構,或者api內部調用了malloc或者free在修改鏈表的時候。

 

可靠信號術語和語義

在信號產生和遞送之間的時間間隔內,稱信號是未決的。

每一個進程都有一個信號屏蔽字,它規定了當前要阻塞遞送到該進程的信號集,對於每種可能的信號,該屏蔽字都有一位與之相對應,對於某種信號,若其對應位已經被設置則他當前是阻塞的

 

int kill(pid_t pid, int signo)
int raise(int signo);

pid 爲

>0             向進程pid發送信號

<0              向進程爲|pid|的進程發送信號

==0          向調用的進程組中的每一個進程發送信號。而且有向這些進程發送信號的權限。

==-1          向所有進程發送信號,必須有權限。

有權限的定義是:發送者的實際或者有效用戶ID必須等於接受者的實際或者有效用戶ID

 

alarm和pause新哈皮

unsigned int  alarm(unsigned int seconds);

向進程發送SIGALRM信號,其默認動作是終止該進程

alarm在設置鬧鐘時間的時候,如果之前進程設置了另外一個鬧鐘時間,那麼alarm就返回之前的剩餘值。

如果seconds爲0表示取消以前的鬧鐘

 

int pause()

pause函數使調用進程掛起知道捕捉到一個信號,只有執行了一個信號處理程序,並從中返回,pause纔會返回。

 

信號集

sigset_t 表示信號集

函數

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t* set);
int sigaddset(sigset_t *set, int signo);
int sigdeleteset(sigset_t* set, int signo);
int sigismember(const sigset_t* set, intsigno):

設置信號屏蔽字

int sigprocmask(int how, constsigset_t  *set, sigset_t  *oset);

how:用於指定信號修改的方式,可能選擇有三種
SIG_BLOCK //加入信號到進程屏蔽。
SIG_UNBLOCK //從進程屏蔽裏將信號刪除。
SIG_SETMASK //將set的值設定爲新的進程屏蔽。

 

查看當前進程中未決的信號

int sigpending(sigset_t *set),在set中獲取當前進程未決的信號集類型

 

sigaction函數的功能是檢查或修改與指定信號相關聯的處理動作(可同時兩種操作)。

他是POSIX的信號接口,而signal()是標準C的信號接口(如果程序必須在非POSIX系統上運行,那麼就應該使用這個接口)

給信號signum設置新的信號處理函數act,同時保留該信號原有的信號處理函數oldact

int sigaction(int signo,const struct sigaction *restrict act,

              struct sigaction *restrict oact);

結構sigaction定義如下:

struct sigaction{
  void (*sa_handler)(int);
   sigset_t sa_mask;
  int sa_flag;
  void (*sa_sigaction)(int,siginfo_t *,void *);
};

sa_handler字段包含一個信號捕捉函數的地址

sa_mask字段說明了一個信號集,在調用該信號捕捉函數之前,這一信號集要加進進程的信號屏蔽字中。僅當從信號捕捉函數返回時再將進程的信號屏蔽字復位爲原先值。

sa_flag是一個選項,主要理解兩個

SA_INTERRUPT 由此信號中斷的系統調用不會自動重啓
SA_RESTART 由此信號中斷的系統調用會自動重啓

SA_SIGINFO 提供附加信息,一個指向siginfo結構的指針以及一個指向進程上下文標識符的指針

 

 

sigsetjmp和siglongjmp

1. 原型:

#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);
直接調用則返回0, 從siglongjmp調用返回則返回非0值.
void siglongjmp(sigjmp_buf env, int val);

可見發現sigsetjmp比setjmp多了一個參數savemask, 如果非0, 則sigsetjmp在env中保存進程的當前信號屏蔽字

 

sigsuspend函數

      #include <signal.h>
       int sigsuspend(const sigset_t *sigmask)

也就是說,sigsuspend後,進程就掛在那裏,等待着開放的信號的喚醒。系統在接受到信號後,馬上就把現在的信號集還原爲原來的,然後調用處理函數。

 

void abot()函數向進程發送SIGABRT信號

發佈了83 篇原創文章 · 獲贊 8 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章