linux 信号处理

来源:互联网 发布:微信报码编码软件 编辑:程序博客网 时间:2024/06/05 20:11

                  当发送一个a信号给一个进程时,会强迫该进程转向不同的执行流,即执行特定的信号处理函数,在信号处理函数中,其内部实现会可能会调用系统调用来完成它的工作,这样进程会进入内核态,如果此时又有一个信号b发送给该进程,在进程返回原来的a信号处理函数之前,内核会强迫该进程执行信号b的信号处理函数,如果信号的信号b处理函数的内部实现也调用了和信号a处理函数中的实现函数,而该函数不是一个可重入函数,即该函数使用了全局的一个变量,则会导致信号a的处理函数对全局数据的不致性观察(全局数据可能已经被信号b的处理函数更改),这样会导致数据的崩溃。因此在信号处理函数的实现中,调用的相关函数应该是可重入的(没有引用全局的变量),或者本身不会在生成信号。

                  信号的内核实现,每个进程的进程描述符里面有几个和信号相关的字段,对应的主要数据结构为信号描述符和信号处理描述符,一个私有的信号链表和线程组共享的信号链表。      内核在实现进程响应信号的实现过程是比较巧妙的,在进程从内核态向用户态转换之间,内核会先检查该进程有没有挂起的信号,如果有的话第一步会在进程用户态堆栈中保存当前内核上下文的一些信息,堆栈顶部保存的是一个系统调用的首地址,这就确保了当信号处理函数执行完毕后,ret指令会将栈顶的数据弹到ip寄存器中,这样信号处理函数执行完毕后,进程会马上执行这个系统调用,该系统调用的主要作用就是恢复原先进程进入内核之前的状态,清空上一步用户栈中保存的信息。第二步会修改当前内核栈中的数据,主本是和用户态进程相关的几个寄存器的值(regs->cs, regs->esp, regs->ip),把这些相关的寄存器值设置为信号处理函数的地址,这样当进程从内核态返回用户态时,进程的执行流不会执行原来被打断的那个point,而是去执行相关的信号处理函数