Linux信号透彻分析理解与各种实例讲解( 二 )


在系统调用或中断返回用户态的前夕 , 内核会检查未决信号集 , 进行相应的信号处理 。
(3)处理过程:
程序运行在用户态时->进程由于系统调用或中断进入内核->转向用户态执行信号处理函数->信号处理函数完毕后进入内核->返回用户态继续执行程序
首先程序执行在用户态 , 在进程陷入内核并从内核返回的前夕 , 会去检查有没有信号没有被处理 , 如果有且没有被阻塞就会调用相应的信号处理程序去处理 。 首先 , 内核在用户栈上创建一个层 , 该层中将返回地址设置成信号处理函数的地址 , 这样 , 从内核返回用户态时 , 就会执行这个信号处理函数 。 当信号处理函数执行完 , 会再次进入内核 , 主要是检测有没有信号没有处理 , 以及恢复原先程序中断执行点 , 恢复内核栈等工作 , 这样 , 当从内核返回后便返回到原先程序执行的地方了 。
信号处理函数的过程大概是这样了 。
需要C/C++ Linux高级服务器架构师学习资料后台私信“资料”(包括C/C++ , Linux , golang技术 , Nginx , ZeroMQ , MySQL , Redis , fastdfs , MongoDB , ZK , 流媒体 , CDN , P2P , K8S , Docker , TCP/IP , 协程 , DPDK , ffmpeg等)
Linux信号透彻分析理解与各种实例讲解文章插图
第三部分: 基本的信号处理函数
首先看一个两个概念: 信号未决与信号阻塞
信号未决: 指的是信号的产生到信号处理之前所处的一种状态 。 确切的说 , 是信号的产生到信号注销之间的状态 。
信号阻塞: 指的是阻塞信号被处理 , 是一种信号处理方式 。
1. 信号操作
信号操作最常用的方法是信号的屏蔽 , 信号屏蔽主要用到以下几个函数:
int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigaddset(sigset_t *set,int signo);int sigdelset(sigset_t *set,int signo);int sigismemeber(sigset_t* set,int signo);int sigprocmask(int how,const sigset_t*set,sigset_t *oset); 信号集 , 信号掩码 , 未决集
信号集: 所有的信号阻塞函数都使用一个称之为信号集的结构表明其所受到的影响 。
信号掩码:当前正在被阻塞的信号集 。
未决集: 进程在收到信号时到信号在未被处理之前信号所处的集合称为未决集 。
可以看出 , 这三个概念没有必然的联系 , 信号集指的是一个泛泛的概念 , 而未决集与信号掩码指的是具体的信号状态 。
对于信号集的初始化有两种方法: 一种是用sigemptyset使信号集中不包含任何信号 , 然后用sigaddset把信号加入到信号集中去 。
另一种是用sigfillset让信号集中包含所有信号 , 然后用sigdelset删除信号来初始化 。
sigemptyset()函数初始化信号集set并将set设置为空 。
sigfillset()函数初始化信号集 , 但将信号集set设置为所有信号的集合 。
sigaddset()将信号signo加入到信号集中去 。
sigdelset()从信号集中删除signo信号 。
sigprocmask()将指定的信号集合加入到进程的信号阻塞集合中去 。 如果提供了oset,那么当前的信号阻塞集合将会保存到oset集全中去 。
参数how决定了操作的方式:
SIG_BLOCK 增加一个信号集合到当前进程的阻塞集合中去
SIG_UNBLOCK 从当前的阻塞集合中删除一个信号集合
SIG_SETMASK 将当前的信号集合设置为信号阻塞集合
下面看一个例子:
#includeint sigaction(int signo,const struct sigaction *act,struct sigaction *oldact); 执行结果:
SIGINT singal blockedblock 0block 1block 2block 3block 4block 5block 6block 7block 8block 9在执行到block 3时按下了CTRL+C并不会终止 , 直到执行到block9后将集合从阻塞集合中移除 。 [root@localhost C]# ./s1SIGINT singal blockedblock 0block 1block 2block 3block 4block 5block 6block 7block 8block 9SIGINT SINGAL unblokcedunblock 0unblock 1由于此时已经解除了阻塞 , 在unblock1后按下CTRL+C则立即终止 。
2. 信号处理函数
struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int,siginfo_t*,void*);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);} 这个函数主要是用于改变或检测信号的行为 。
第一个参数是变更signo指定的信号 , 它可以指向任何值 , SIGKILL,SIGSTOP除外
第二个参数,第三个参数是对信号进行细粒度的控制 。
如果*act不为空 , *oldact不为空 , 那么oldact将会存储信号以前的行为 。 如果act为空 , *oldact不为空 , 那么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);} 参数含义: