首先,先说明几个概念:
信号递达:实际执行信号的动作
信号未决:信号从产生到递达的状态
信号处理有三种情况:默认、忽略、用户自定义
每个信号都有三个表:block、pending、handler
block:表示信号是否被阻塞。用数据类型sigset_t存储的,0表示不被阻塞,1表示被阻塞。被阻塞的信号在产生时保持未决状态,直到进程解除对信号的阻塞,才执行递达的动作。
pending:未决标志。信号产生却没递达的为1,直到信号递达才清除该标志。用数据类型sigset_t存储的。
handler:存放的是信号处理函数的函数指针,默认是SIG_DEL、忽略是SIG_IGN。
信号处理过程:
执行main函数时发生中断或异常切换到内核态。中断处理完毕后从内核态返回用户态之前处理当前进程中可以递达(未决且未阻塞)的信号。如果是默认或忽略,处理之后直接返回main函数上下文执行。如果信号处理动作为自定义的信号处理函数则返回用户模式执行信号处理函数(不是回到主控制流,它们不存在调用与被调用的关系,是独立的控制流程),信号处理函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。如果没有信号要递达,返回main函数的上下文继续执行。
信号集操作函数
int sigemptyset(sigset_t *set);//初始化信号集,对应bit位清零
int sigfillset(sigset_t *set);//初始化信号集,对应bit位置位
int sigaddset(sigset_t *set,int signo);//添加signo信号
int sigdelset(sigset_t *set,int signo);//删除signo信号
int sigismember(sigset_t *set,int signo);//判断信号集有效信号中是否包含signo信号
int sigpromask(int how,const sigset_t *set,sigset_t *oset);
//读取或更改进程的信号屏蔽字
//oset表示当前的信号屏蔽字,set表示要更改成的信号屏蔽字
//how表示如何修改:SIG_BLOCK,添加信号屏蔽字 SIG_UNBLOCK删除信号屏蔽字
SIG_SETMASK设置当前信号屏蔽字为set
int sigpending(sigset_t *set);//读取当前进程的未决信号集,保存至set
小案例:得到未决信号集
1 #include<signal.h>
2 #include<unistd.h>
3 #include<stdio.h>
4
5 void print(sigset_t *set)
6 {
7 int i = 0;
8 for(i=1; i<32; i++)
9 {
10 printf("%d",sigismember(set,i));
11 fflush(stdout);
12 }
13 printf("\n");
14 }
15
16 int main()
17 {
18 sigset_t block,pending,oset;
19 sigemptyset(&block);
20 sigaddset(&block,SIGINT);
21 sigprocmask(SIG_SETMASK,&block,&oset);
22
23 while(1)
24 {
25 sigpending(&pending);
26 print(&pending);
27 sleep(1);
28 }
29 }
可重入函数
一个函数被不同的控制流程调用,有可能在第一次调用还没返回值时就再次进入该函数,这叫重入。一些因为重入而导致错乱的函数称为不可重入函数。例如,调用了malloc/free,
调用了标准I/O库函数。
小案例:mysleep
1 #include<unistd.h>
2 #include<stdlib.h>
3 #include<stdio.h>
4 #include<signal.h>
5
6 void alar()
7 {
8
9 }
10
11 int mysleep(int seconds)
12 {
13 struct sigaction newact,oldact;
14 newact.sa_handler = alar;
15 newact.sa_flags = 0;
16 sigemptyset(&newact.sa_mask);
17 sigaction(SIGALRM,&newact,&oldact);
18
19 sigset_t newset,oldset,susset;
20 sigemptyset(&newset);
21 sigaddset(&newset,SIGALRM);
22 sigprocmask(SIG_BLOCK,&newset,&oldset);
23
24 susset = oldset;
25 sigdelset(&susset,SIGALRM);
26 alarm(seconds);
27 sigsuspend(&susset);
28
29 int unslept = alarm(0);
30 sigaction(SIGALRM,&oldact,NULL);
31 sigprocmask(SIG_SETMASK,&oldset,NULL);
32 return unslept;
33
34 }
35
36 int main()
37 {
38 while(1)
39 {
40 printf("i am main\n");
41 mysleep(1);
42 }
43 }