1. 信号的基本概念
1.1 基本概念
(1)信号(signal)机制是linux系统中最为古老的进程之间的通信机制,解决进程在正常运行过程中被中断的问题,导致进程的处理流程会发生变化。
(2)信号本质上是在软件层次上对中断机制的一种模拟,是一种软件中断。
(3)信号是异步事件
①不可预见;
②信号有自己的名称和编号(/usr/include/bits/signum.h);
③信号和异常处理机制;
(4)信号发生的来源
①硬件来源:比如我们按下了键盘或者其它硬件故障,信号是由硬件驱动程序产生。
②软件来源:最常用发送信号的系统函数是kill、raise、alarm和settimer等函数,软件来源还包括了一些非法运算等操作,软件设置等条件(如gdb调试),信号是由内核产生的。
1.2 系统信号
信号 |
说明 |
默认动作 |
SIGHUP(1) |
连接断开信号。登录linux时,系统会分配给用户一个终端(session)。在这个终端运行的所有程序,包括前台和后台进程组,一般都属于这个session。当用户退出linux时,前台进程组和所有有终端输出的进程都会收到SIGHUP信号。 |
终止进程 |
SIGINT(2) |
程序终止信号,在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程 |
终止进程 |
SIGQUIT(3) |
和SIGINT类似,但由QUIT字符(通常是Ctrl-\)来控制。进程在因收到SIGQUIT退出时会产生core文件,在这个意义上类似于一个程序错误信号。 |
终止+core |
SIGILL(4) |
执行非法指令。通常是因为可执行文件本身出现错误,或者试图执行数据段、堆栈溢出时也可能产生这个信号。 |
终止+core |
SIGTRAP(5) |
由断点指令或其它trap指令产生。由debugger使用 |
终止+core |
SIGABRT(6) |
异常终止,调用abort函数生成的信号 |
终止+core |
SIGBUS(7) |
非法地址,包括内存对齐出错。 |
终止+core |
SIGFPE(8) |
在发生致命的算术运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术错误。 |
终止+core |
SIGKILL(9) |
用来立即结束程序的运行。本信号不能被阻塞、处理和忽略。 |
终止 |
SIGUSR1(10) |
留给用户使用 |
终止 |
SIGSEGV(11) |
试图访问未分配给自己的内存,或试图往没有写权限的内存地址写数据 |
终止+core |
SIGUSR2(12) |
留给用户使用 |
终止 |
SIGPIPE(13) |
写到无读进程的管道。即读管道没有打开或者意外终止,这时写进程会收到该信号 |
终止 |
SIGALRM(14) |
时钟定时信号,计算的是实际的时间或时钟时间。alarm函数使用该信号。 |
终止 |
SIGTERM(15) |
程序结束(terminate)信号,与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出。只有在进程终止不了,才SIGKILL |
终止 |
SIGCHLD(17) |
子进程结束时,父进程会收到该信号。如果父进程先终止,由子进程的终止由init进程接管。 |
忽略 |
SIGCONT(18) |
让一个停止(stopped)的进程继续执行。本信号不能被阻塞。可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作。如重新显示提示符。 |
继续/忽略 |
SIGSTOP(19) |
停止(stopped)进程的执行。注意它和terminate以及interrupt的区别:该进程还未结束,只是暂停。本信号不能被阻塞,处理或忽略 |
暂停进程 |
SIGTSTP(20) |
停止进程的运行,但该信号可以被处理或忽略。用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号。 |
暂停进程 |
SIGTTIN(21) |
当后台作业要从用户终端读数据时,该作业中的所有进程会收到SIGTTIN信号。缺省这些进程会停止执行。 |
暂停进程 |
SIGTTOU(22) |
类似于SIGTTIN,但在写终端(或修改终端模式)时收到。 |
暂停进程 |
SIGURG(23) |
有“紧急”数据或out-of-band数据到达socket时产生。 |
忽略 |
SIGXCPU(24) |
超过CPU时间资源限制。这个限制可以由getrlimit/setrlimit来读取/改变。 |
终止+core |
SIGXFSZ(25) |
当进程企图扩大文件以致于超过文件大小资源限制 |
终止+core |
SIGVTALRM(26) |
虚拟时钟信号。类似于SIGALARM,但是计算的是该进程占用CPU的时间 |
终止 |
SIGPROF(27) |
类似于SIGALARM/SIGVTALARM,但包括进程用的CPU时间以及系统调用的时间。 |
终止 |
SIGWINCH(28) |
终端窗口大小改变时发出 |
忽略 |
SIGIO(29) |
文件描述符准备就绪,可以开始进行输入/输出操作。 |
终止/忽略 |
SIGPWR(30) |
电源失效/重启动 |
终止/忽略 |
SIGSYS(31) |
非法的系统调用 |
终止+core |
1.3 信号的处理方式
处理方式 |
说明 |
忽略信号 |
①SIGKILL和SIGSTOP永远不能忽略②忽略硬件异常;③进程启动时SIGUSR1和SIGUSR2两个信号被忽略 |
执行默认操作 |
每个信号有默认动作,大部分信号默认动作是终止进程。 |
捕获信号 |
①告诉内核出现信号时调用自己的处理函数 ②SIGKILL和SIGSTOP不能被捕获 |
1.4 信号处理机制
(1)进程如何发现和接受信号
①信号是异步的,进程不可能一直等待信号的到来,也不知道信号会到来。
②信号的接收不是用户进程完成的,而是由内核代理。
③当进程p2向进程p1发送信号后,内核接受到信号,并将其放入p1的信号队列中。当p1进程陷入内核态并准备返回用户态时,会检查信号队列然后根据相应的信号调取相应的信号处理函数。
(2)信号的检测和响应时机
①当前进程由于系统调用、中断或异常而进入系统空间以后(陷入内核态),从系统空间返回到用户空间的前夕会检测信号队列
②当前进程在内核进入睡眠以后刚被唤醒或者由于不可忽略的信号存在而需提前返回到用户空间时,也会检测信号队列并调用相应的信号处理函数。
(3)信号处理函数执行完毕
当信号处理函数执行完毕之后,进程会主动调用sigreturn()再次回到内核。查看有没有其它信号需要处理。如果没有,内核会做一些善后工作,然后返回用户空间,至此完成了一次(或几次)信号的处理。
1.5 信号的变革
(1)信号出现在早期的Unix中,但早期的信号模型是不可靠的。
(2)BSD和System V分别对早期信号进行扩展,但是相互不兼容。
(3)POSIX统一了上述两种模型,提供了可靠信号模型。