Linux在执行信号处理的过程中对堆栈的处理


今天, 写代码的时候碰到了一点UNIX信号相关的问题, 于是晚上就查阅了Linux信号实现的机制, 大体上有个总结:

执行一个信号处理程序是件相当复杂的任务,因为在用户态和内核态之间切换时需要谨慎地处理栈中的内容。 信号处理程序是用户态进程所定义的函数,并包含在用户态的代码段中。handle_signal( )函数运行在内核态而信号处理程序运行在用户态,这就意味着在当前进程恢复 “正常”执行之前,它必须首先执行用户态的信号处理程序。此外,当内核打算恢复进程的正常执行时,内核态堆栈不再包含被中断程序的硬件上下文,因为每当从内核态向用户态转换时,内核态堆栈被清空。而另外一个复杂性是因为信号处理程序可以调用系统调用,在这种情况下,执行了系统调用的服务例程以后,控制权必须返回到信号处理程序而不是到被中断程序的代码。Linux所采用的解决方法是: 一个非阻塞的信号发送给一个进程。当中断或异常发生时,进程切换到内核态。正要返回到用户态前,内核执行do_signal()函数,这个函数又依次处理信号( 通过调用handle_signal() )和建立用户态堆栈(通过调用setup_frame()或setup_rt_frame() )。当进程又切换到用户态时,因为信号处理程序的起始地址被强制放进程序计数器中,因此开始执行信号处理程序。当处理程序终止时,setup_frame() 或setup_rt_frame()函数放在用户态堆栈中的返回代码就被执行。这个代码调用sigreturn()系统调用,它的服务例程把正常程序的用户态堆栈硬件上下文拷贝到内核态堆栈,并把用户态堆栈恢复回到它原来的状态(通过调用restore_sigcontext() )。当这个系统调用结束时,普通进程因此能恢复自己的执行。

针对以上的实现, 如果仔细的分析源代码, 可能是件艰苦的差事!

相关内容