目录
进程什么时候检测处理信号?以及内核如何实现信号的捕捉?
sigaction
volatile
信号由操作系统发送给相应的进程,进程保存信号,最后再捕捉处理信号。
进程什么时候检测处理信号?以及内核如何实现信号的捕捉?

操作系统执行状态由内核态返回到用户态的时候,进行信号的检测和处理!
内核态和用户态是操作系统中两种不同的执行状态,限制不同程序的访问权限。由于系统调用是内核的数据,因此OS要切换到内核态(CPU内部的esc寄存器也会切换到内核态),两者配合这管理运行该程序。
上图是信号被检测处理和捕捉的示意图。
我们对于该示意图有如下分析:
 
 如果信号的处理动作是用户自定义函数, 
 在信号递达时就调用这个函数, 
 这称为 
 捕捉信号 
 。由于信号处理函数的代码是在用户空间的, 
 处理过程比较复杂, 
 举例如下: 
 用户程序定义了 
 SIGQUIT 
 信号的处理函 
 数sighandler 
 。当前正在执行main 
 函数, 
 这时如果碰到系统调用(这里最常见)、中断或异常OS切换到内核态。在系统调用完毕后要返回用户态的 
 main 
 函数之前检查到有信号SIGQUIT 
 递达。内核决定返回用户态后不是恢复 
 main 
 函数的上下文继续执行, 
 而是执行 
 sighandler 
 函数 
 ,sighandler和 
 main 
 函数使用不同的堆栈空间 
 , 
 它们之间不存在调用和被调用的关系, 
 是两个独立的控制流程。 
  sighandler 
 函数返回后自动执行特殊的系统调用 
 sigreturn 
 再次进入内核态。如果没有新的信号要递达 
 , 
 这次再返回用户态就是恢复main 
 函数的上下文继续执行了。 
 
 
sigaction
 
 int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);  
 
 
 头文件:<signal.h>  
 
 
功能:sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回-1。
参数:signo 是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体。
struct sigaction结构体:

volatile
 
 今天我们站在信号的角度重新理解一下该关键字: 
 
 
#include <stdio.h>
#include <signal.h>
int flag = 0;
void handler(int sig)
{
 printf("chage flag 0 to 1\n");
 flag = 1;//在优化条件下, flag变量可能被直接优化到CPU内的寄存器中
}
int main()
{
 signal(2, handler);
 while(!flag);
 printf("process quit normal\n");
 return 0;
} 
  标准情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while 条件不满足,退出循环,进程退出。 
 
 
  
 makefile里的形成可执行文件时:gcc -o signal signal.c -O1/2/3,优化flag变量
 
  volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作。 
 
 









![[web]-反序列化漏洞-easy入门](https://i-blog.csdnimg.cn/direct/3868df69b97e4c2cb0b33b2d26f0e4b4.png)









