信号机制是Unix的一大特色,因为是特色,所以很多同学在编程时,有些不能理解(超出理解范围?)。
本文对Linux信号机制做一个分析。
常见signal使用如下:
void mysig(){
printf("got a sig!\n");
}
int main() {
printf("process id is %d !\n",getpid());
signal(SIGINT, mysig);
for (;;) ;
}
当我们在控制台按Ctrl + C时,控制台会打印出"got a sig!"。
这个过程到底发生了什么?
如果你没有深入思考过操作系统的工作原理,就算是写过几年的C程序,也是一头雾水。
如果是初学C,都知道,C程序是从main函数开始,跑到最后一行,顺序执行!signal的概念完全就是个怪胎!
signal的内核操作过程如下:
1,signal()系统调用,发生0x80中断(陷阱),调用sys_signal()。
2,sys_signal()获取到传入的信号编号(SIGINT等宏定义),以及对应的handler,把它注册到current宏的sigaction[signum-1],current宏指向了正在执行的task_struct,而sigaction是task_struct的一个成员。
3,中断服务程序执行完毕之后,准备返回用户程序,返回之前,检查当前进程可以处理的信号——此时,信号可能(一般)还没发生。
4,程序员按了Ctrl +C,内核接收到这个信号了,对应的sigaction的选项被标记。
5,内核又发生了中断,返回用户程序前,检查可以处理的信号,发现有信号可以处理,do_signal(),跳转到注册的handler(),程序员感觉到穿越了(也就是最难理解的地方)
6,handler()执行完毕之后,执行特殊系统调用,返回内核态。
7,从内核态返回用户模式,出栈,恢复到中断发生之前,接着执行之前的代码。
所以,关键还是对中断的理解——理解了中断,linux内核就理解了三分之一!